diff --git a/.release-please-manifest.json b/.release-please-manifest.json
index 4e9d6c7e..32ac6588 100644
--- a/.release-please-manifest.json
+++ b/.release-please-manifest.json
@@ -1,3 +1,3 @@
{
- ".": "7.1.1"
+ ".": "8.0.0"
}
diff --git a/.stats.yml b/.stats.yml
index f035d349..e75a1bc7 100644
--- a/.stats.yml
+++ b/.stats.yml
@@ -1,4 +1,4 @@
configured_endpoints: 42
-openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/imagekit-inc%2Fimagekit-c7ad6f552b38f2145781847f8b390fa1ec43068d64e45a33012a97a9299edc10.yml
-openapi_spec_hash: 50f281e91210ad5018ac7e4eee216f56
-config_hash: 74a8263b80c732a2b016177e7d56bb9c
+openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/imagekit-inc%2Fimagekit-9d184cb502ab32a85db2889c796cdfebe812f2a55a604df79c85dd4b5e7e2add.yml
+openapi_spec_hash: a9aa620376fce66532c84f9364209b0b
+config_hash: 71cab8223bb5610c6c7ca6e9c4cc1f89
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 0617e7cc..66269322 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,5 +1,63 @@
# Changelog
+## 8.0.0 (2025-12-18)
+
+Full Changelog: [v7.1.1...v8.0.0](https://github.com/imagekit-developer/imagekit-nodejs/compare/v7.1.1...v8.0.0)
+
+### ⚠ BREAKING CHANGES
+
+* **mcp:** remove deprecated tool schemes
+* **mcp:** **Migration:** To migrate, simply modify the command used to invoke the MCP server. Currently, the only supported tool scheme is code mode. Now, starting the server with just `node /path/to/mcp/server` or `npx package-name` will invoke code tools: changing your command to one of these is likely all you will need to do.
+
+### Features
+
+* **api:** add GetImageAttributesOptions and ResponsiveImageAttributes schemas; update resource references in main.yaml; remove dummy endpoint ([9ea439a](https://github.com/imagekit-developer/imagekit-nodejs/commit/9ea439a2d0a4c8300d14d4424dc72ab40a67c4d4))
+* **mcp:** add detail field to docs search tool ([f36d795](https://github.com/imagekit-developer/imagekit-nodejs/commit/f36d79523b0613a27afd45d56f4e1e906e6fdfe9))
+* **mcp:** add typescript check to code execution tool ([63ab735](https://github.com/imagekit-developer/imagekit-nodejs/commit/63ab735bf6c8458a53bd66c8c437b45a7aef60fe))
+* **mcp:** enable optional code execution tool on http mcp servers ([cc68e38](https://github.com/imagekit-developer/imagekit-nodejs/commit/cc68e38fa61078db6a5c961e7ed75dad342dc7e8))
+* **mcp:** handle code mode calls in the Stainless API ([eb22f08](https://github.com/imagekit-developer/imagekit-nodejs/commit/eb22f0883fc74c94959fdd97e50d41d940e1aed6))
+* **mcp:** return logs on code tool errors ([6118fe4](https://github.com/imagekit-developer/imagekit-nodejs/commit/6118fe4804be492482268ff25e0afc714bea7613))
+
+
+### Bug Fixes
+
+* **docs:** remove extraneous example object fields ([a043056](https://github.com/imagekit-developer/imagekit-nodejs/commit/a043056abd2f86bcb5a691ac8f5c7ccf8a17663c))
+* **mcp:** add client instantiation options to code tool ([967c8d9](https://github.com/imagekit-developer/imagekit-nodejs/commit/967c8d90503b2e0ed0576b919be09f3b924ec890))
+* **mcpb:** pin @anthropic-ai/mcpb version ([d81e225](https://github.com/imagekit-developer/imagekit-nodejs/commit/d81e22560aab772ee9b241fb44a50561b8837034))
+* **mcp:** correct code tool API endpoint ([f4d2b6c](https://github.com/imagekit-developer/imagekit-nodejs/commit/f4d2b6c9989e8cc6c69badba7de0abb57e6de398))
+* **mcp:** pass base url to code tool ([908fa87](https://github.com/imagekit-developer/imagekit-nodejs/commit/908fa874d20613761caa76cd4b2151524ef87606))
+* **mcp:** return correct lines on typescript errors ([aa7ae07](https://github.com/imagekit-developer/imagekit-nodejs/commit/aa7ae07286cf492a7b1fecce34697006837beeef))
+* **mcp:** return tool execution error on api error ([1e866f8](https://github.com/imagekit-developer/imagekit-nodejs/commit/1e866f8e5254ecc305b3dfee53ec232455143cc4))
+* **mcp:** return tool execution error on jq failure ([d1949db](https://github.com/imagekit-developer/imagekit-nodejs/commit/d1949dbef79859b446ee9ee2c8a2d562568c1cca))
+
+
+### Chores
+
+* **client:** fix logger property type ([6269318](https://github.com/imagekit-developer/imagekit-nodejs/commit/6269318024cd320f3038def32c3d5bf1f1da77a1))
+* extract some types in mcp docs ([de606ba](https://github.com/imagekit-developer/imagekit-nodejs/commit/de606ba3b734389e1c52a9929dbf8487828822e0))
+* **internal:** codegen related update ([b6b0d1a](https://github.com/imagekit-developer/imagekit-nodejs/commit/b6b0d1a7d2f00d9ecaa9e0e630a012c25f6a00f4))
+* **internal:** codegen related update ([26acc3a](https://github.com/imagekit-developer/imagekit-nodejs/commit/26acc3a9fe08c7c478eed956dd553333bd8cf210))
+* **internal:** codegen related update ([662aa87](https://github.com/imagekit-developer/imagekit-nodejs/commit/662aa87091dc519bb811554438eaf978660d035e))
+* **internal:** codegen related update ([8c9026a](https://github.com/imagekit-developer/imagekit-nodejs/commit/8c9026ace5d217264e5753c01309a02a2c09095e))
+* **internal:** grammar fix (it's -> its) ([71e22a3](https://github.com/imagekit-developer/imagekit-nodejs/commit/71e22a30017324842fed5ab08ee1efbb1eecb6d2))
+* **internal:** upgrade eslint ([310bf0d](https://github.com/imagekit-developer/imagekit-nodejs/commit/310bf0d0cc1d5b15d08a2cbb483a9969ebf4f11d))
+* **internal:** use npm pack for build uploads ([bdfd369](https://github.com/imagekit-developer/imagekit-nodejs/commit/bdfd369118542dad02cf8a0fae8713d0d8bea4eb))
+* mcp code tool explicit error message when missing a run function ([6678ee1](https://github.com/imagekit-developer/imagekit-nodejs/commit/6678ee13cc1eee5ce1ac51b672144be77c38e9ea))
+* **mcp:** add friendlier MCP code tool errors on incorrect method invocations ([636829d](https://github.com/imagekit-developer/imagekit-nodejs/commit/636829d18a7dda730b65c0549298258afcea6341))
+* **mcp:** add line numbers to code tool errors ([25e4e59](https://github.com/imagekit-developer/imagekit-nodejs/commit/25e4e59f434c07c2d9afeef3f548dd99e250a7ab))
+* **mcp:** clarify http auth error ([00789ac](https://github.com/imagekit-developer/imagekit-nodejs/commit/00789acfb9ceb07af0cd03b1951090f430691592))
+* **mcp:** remove deprecated tool schemes ([b1a0e60](https://github.com/imagekit-developer/imagekit-nodejs/commit/b1a0e607e55f27ffed93b2862e8f4466bc609809))
+* **mcp:** update lockfile ([0703827](https://github.com/imagekit-developer/imagekit-nodejs/commit/07038271d5ec459516a8a936eb49f31490ccf6b0))
+* **mcp:** upgrade jq-web ([0750770](https://github.com/imagekit-developer/imagekit-nodejs/commit/075077081fc5826a4502a76a2abc40788f7915a3))
+* use latest @modelcontextprotocol/sdk ([f7b9b4e](https://github.com/imagekit-developer/imagekit-nodejs/commit/f7b9b4e55919b644d9445730c03c8972ecdfe0b7))
+* use structured error when code execution tool errors ([451f306](https://github.com/imagekit-developer/imagekit-nodejs/commit/451f306f6328e6c48374d0525dad9a0ddc6511d6))
+
+
+### Documentation
+
+* **mcp:** add a README button for one-click add to Cursor ([a7575d3](https://github.com/imagekit-developer/imagekit-nodejs/commit/a7575d308e3038715964f7416284bb012e27b240))
+* **mcp:** add a README link to add server to VS Code or Claude Code ([2a90d28](https://github.com/imagekit-developer/imagekit-nodejs/commit/2a90d2802e4814d97ec5bba77097eec2f0a5a718))
+
## 7.1.1 (2025-10-06)
Full Changelog: [v7.1.0...v7.1.1](https://github.com/imagekit-developer/imagekit-nodejs/compare/v7.1.0...v7.1.1)
diff --git a/api.md b/api.md
index 86719ecf..fc87a76f 100644
--- a/api.md
+++ b/api.md
@@ -4,10 +4,12 @@ Types:
- BaseOverlay
- Extensions
+- GetImageAttributesOptions
- ImageOverlay
- Overlay
- OverlayPosition
- OverlayTiming
+- ResponsiveImageAttributes
- SolidColorOverlay
- SolidColorOverlayTransformation
- SrcOptions
diff --git a/package.json b/package.json
index efd98c94..9fd98223 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
{
"name": "@imagekit/nodejs",
- "version": "7.1.1",
+ "version": "8.0.0",
"description": "Offical NodeJS SDK for ImageKit.io integration",
"author": "Image Kit ",
"types": "dist/index.d.ts",
@@ -37,7 +37,7 @@
"@types/node": "^20.17.6",
"@typescript-eslint/eslint-plugin": "8.31.1",
"@typescript-eslint/parser": "8.31.1",
- "eslint": "^9.20.1",
+ "eslint": "^9.39.1",
"eslint-plugin-prettier": "^5.4.1",
"eslint-plugin-unused-imports": "^4.1.4",
"iconv-lite": "^0.6.3",
diff --git a/packages/mcp-server/README.md b/packages/mcp-server/README.md
index 38260a76..d3562879 100644
--- a/packages/mcp-server/README.md
+++ b/packages/mcp-server/README.md
@@ -25,7 +25,7 @@ For clients with a configuration JSON, it might look something like this:
"mcpServers": {
"imagekit_nodejs_api": {
"command": "npx",
- "args": ["-y", "@imagekit/api-mcp", "--client=claude", "--tools=dynamic"],
+ "args": ["-y", "@imagekit/api-mcp"],
"env": {
"IMAGEKIT_PRIVATE_KEY": "My Private Key",
"OPTIONAL_IMAGEKIT_IGNORES_THIS": "My Password",
@@ -36,97 +36,45 @@ For clients with a configuration JSON, it might look something like this:
}
```
-## Exposing endpoints to your MCP Client
+### Cursor
-There are two ways to expose endpoints as tools in the MCP server:
+If you use Cursor, you can install the MCP server by using the button below. You will need to set your environment variables
+in Cursor's `mcp.json`, which can be found in Cursor Settings > Tools & MCP > New MCP Server.
-1. Exposing one tool per endpoint, and filtering as necessary
-2. Exposing a set of tools to dynamically discover and invoke endpoints from the API
+[](https://cursor.com/en-US/install-mcp?name=@imagekit/api-mcp&config=eyJjb21tYW5kIjoibnB4IiwiYXJncyI6WyIteSIsIkBpbWFnZWtpdC9hcGktbWNwIl0sImVudiI6eyJJTUFHRUtJVF9QUklWQVRFX0tFWSI6IlNldCB5b3VyIElNQUdFS0lUX1BSSVZBVEVfS0VZIGhlcmUuIiwiT1BUSU9OQUxfSU1BR0VLSVRfSUdOT1JFU19USElTIjoiU2V0IHlvdXIgT1BUSU9OQUxfSU1BR0VLSVRfSUdOT1JFU19USElTIGhlcmUuIiwiSU1BR0VLSVRfV0VCSE9PS19TRUNSRVQiOiJTZXQgeW91ciBJTUFHRUtJVF9XRUJIT09LX1NFQ1JFVCBoZXJlLiJ9fQ)
-### Filtering endpoints and tools
+### VS Code
-You can run the package on the command line to discover and filter the set of tools that are exposed by the
-MCP Server. This can be helpful for large APIs where including all endpoints at once is too much for your AI's
-context window.
+If you use MCP, you can install the MCP server by clicking the link below. You will need to set your environment variables
+in VS Code's `mcp.json`, which can be found via Command Palette > MCP: Open User Configuration.
-You can filter by multiple aspects:
+[Open VS Code](https://vscode.stainless.com/mcp/%7B%22name%22%3A%22%40imagekit%2Fapi-mcp%22%2C%22command%22%3A%22npx%22%2C%22args%22%3A%5B%22-y%22%2C%22%40imagekit%2Fapi-mcp%22%5D%2C%22env%22%3A%7B%22IMAGEKIT_PRIVATE_KEY%22%3A%22Set%20your%20IMAGEKIT_PRIVATE_KEY%20here.%22%2C%22OPTIONAL_IMAGEKIT_IGNORES_THIS%22%3A%22Set%20your%20OPTIONAL_IMAGEKIT_IGNORES_THIS%20here.%22%2C%22IMAGEKIT_WEBHOOK_SECRET%22%3A%22Set%20your%20IMAGEKIT_WEBHOOK_SECRET%20here.%22%7D%7D)
-- `--tool` includes a specific tool by name
-- `--resource` includes all tools under a specific resource, and can have wildcards, e.g. `my.resource*`
-- `--operation` includes just read (get/list) or just write operations
+### Claude Code
-### Dynamic tools
+If you use Claude Code, you can install the MCP server by running the command below in your terminal. You will need to set your
+environment variables in Claude Code's `.claude.json`, which can be found in your home directory.
-If you specify `--tools=dynamic` to the MCP server, instead of exposing one tool per endpoint in the API, it will
-expose the following tools:
-
-1. `list_api_endpoints` - Discovers available endpoints, with optional filtering by search query
-2. `get_api_endpoint_schema` - Gets detailed schema information for a specific endpoint
-3. `invoke_api_endpoint` - Executes any endpoint with the appropriate parameters
-
-This allows you to have the full set of API endpoints available to your MCP Client, while not requiring that all
-of their schemas be loaded into context at once. Instead, the LLM will automatically use these tools together to
-search for, look up, and invoke endpoints dynamically. However, due to the indirect nature of the schemas, it
-can struggle to provide the correct properties a bit more than when tools are imported explicitly. Therefore,
-you can opt-in to explicit tools, the dynamic tools, or both.
-
-See more information with `--help`.
-
-All of these command-line options can be repeated, combined together, and have corresponding exclusion versions (e.g. `--no-tool`).
-
-Use `--list` to see the list of available tools, or see below.
-
-### Specifying the MCP Client
-
-Different clients have varying abilities to handle arbitrary tools and schemas.
-
-You can specify the client you are using with the `--client` argument, and the MCP server will automatically
-serve tools and schemas that are more compatible with that client.
-
-- `--client=`: Set all capabilities based on a known MCP client
-
- - Valid values: `openai-agents`, `claude`, `claude-code`, `cursor`
- - Example: `--client=cursor`
-
-Additionally, if you have a client not on the above list, or the client has gotten better
-over time, you can manually enable or disable certain capabilities:
-
-- `--capability=`: Specify individual client capabilities
- - Available capabilities:
- - `top-level-unions`: Enable support for top-level unions in tool schemas
- - `valid-json`: Enable JSON string parsing for arguments
- - `refs`: Enable support for $ref pointers in schemas
- - `unions`: Enable support for union types (anyOf) in schemas
- - `formats`: Enable support for format validations in schemas (e.g. date-time, email)
- - `tool-name-length=N`: Set maximum tool name length to N characters
- - Example: `--capability=top-level-unions --capability=tool-name-length=40`
- - Example: `--capability=top-level-unions,tool-name-length=40`
-
-### Examples
-
-1. Filter for read operations on cards:
-
-```bash
---resource=cards --operation=read
```
-
-2. Exclude specific tools while including others:
-
-```bash
---resource=cards --no-tool=create_cards
+claude mcp add --transport stdio imagekit_nodejs_api --env IMAGEKIT_PRIVATE_KEY="Your IMAGEKIT_PRIVATE_KEY here." OPTIONAL_IMAGEKIT_IGNORES_THIS="Your OPTIONAL_IMAGEKIT_IGNORES_THIS here." IMAGEKIT_WEBHOOK_SECRET="Your IMAGEKIT_WEBHOOK_SECRET here." -- npx -y @imagekit/api-mcp
```
-3. Configure for Cursor client with custom max tool name length:
+## Code Mode
-```bash
---client=cursor --capability=tool-name-length=40
-```
+This MCP server is built on the "Code Mode" tool scheme. In this MCP Server,
+your agent will write code against the TypeScript SDK, which will then be executed in an
+isolated sandbox. To accomplish this, the server will expose two tools to your agent:
-4. Complex filtering with multiple criteria:
+- The first tool is a docs search tool, which can be used to generically query for
+ documentation about your API/SDK.
-```bash
---resource=cards,accounts --operation=read --tag=kyc --no-tool=create_cards
-```
+- The second tool is a code tool, where the agent can write code against the TypeScript SDK.
+ The code will be executed in a sandbox environment without web or filesystem access. Then,
+ anything the code returns or prints will be returned to the agent as the result of the
+ tool call.
+
+Using this scheme, agents are capable of performing very complex tasks deterministically
+and repeatably.
## Running remotely
@@ -154,198 +102,3 @@ A configuration JSON for this server might look like this, assuming the server i
}
}
```
-
-The command-line arguments for filtering tools and specifying clients can also be used as query parameters in the URL.
-For example, to exclude specific tools while including others, use the URL:
-
-```
-http://localhost:3000?resource=cards&resource=accounts&no_tool=create_cards
-```
-
-Or, to configure for the Cursor client, with a custom max tool name length, use the URL:
-
-```
-http://localhost:3000?client=cursor&capability=tool-name-length%3D40
-```
-
-## Importing the tools and server individually
-
-```js
-// Import the server, generated endpoints, or the init function
-import { server, endpoints, init } from "@imagekit/api-mcp/server";
-
-// import a specific tool
-import createCustomMetadataFields from "@imagekit/api-mcp/tools/custom-metadata-fields/create-custom-metadata-fields";
-
-// initialize the server and all endpoints
-init({ server, endpoints });
-
-// manually start server
-const transport = new StdioServerTransport();
-await server.connect(transport);
-
-// or initialize your own server with specific tools
-const myServer = new McpServer(...);
-
-// define your own endpoint
-const myCustomEndpoint = {
- tool: {
- name: 'my_custom_tool',
- description: 'My custom tool',
- inputSchema: zodToJsonSchema(z.object({ a_property: z.string() })),
- },
- handler: async (client: client, args: any) => {
- return { myResponse: 'Hello world!' };
- })
-};
-
-// initialize the server with your custom endpoints
-init({ server: myServer, endpoints: [createCustomMetadataFields, myCustomEndpoint] });
-```
-
-## Available Tools
-
-The following tools are available in this MCP server.
-
-### Resource `customMetadataFields`:
-
-- `create_custom_metadata_fields` (`write`): This API creates a new custom metadata field. Once a custom metadata field is created either through this API or using the dashboard UI, its value can be set on the assets. The value of a field for an asset can be set using the media library UI or programmatically through upload or update assets API.
-- `update_custom_metadata_fields` (`write`): This API updates the label or schema of an existing custom metadata field.
-- `list_custom_metadata_fields` (`read`): This API returns the array of created custom metadata field objects. By default the API returns only non deleted field objects, but you can include deleted fields in the API response.
-
- You can also filter results by a specific folder path to retrieve custom metadata fields applicable at that location. This path-specific filtering is useful when using the **Path policy** feature to determine which custom metadata fields are selected for a given path.
-
-- `delete_custom_metadata_fields` (`write`): This API deletes a custom metadata field. Even after deleting a custom metadata field, you cannot create any new custom metadata field with the same name.
-
-### Resource `files`:
-
-- `update_files` (`write`): This API updates the details or attributes of the current version of the file. You can update `tags`, `customCoordinates`, `customMetadata`, publication status, remove existing `AITags` and apply extensions using this API.
-- `delete_files` (`write`): This API deletes the file and all its file versions permanently.
-
- Note: If a file or specific transformation has been requested in the past, then the response is cached. Deleting a file does not purge the cache. You can purge the cache using purge cache API.
-
-- `copy_files` (`write`): This will copy a file from one folder to another.
-
- Note: If any file at the destination has the same name as the source file, then the source file and its versions (if `includeFileVersions` is set to true) will be appended to the destination file version history.
-
-- `get_files` (`read`): This API returns an object with details or attributes about the current version of the file.
-- `move_files` (`write`): This will move a file and all its versions from one folder to another.
-
- Note: If any file at the destination has the same name as the source file, then the source file and its versions will be appended to the destination file.
-
-- `rename_files` (`write`): You can rename an already existing file in the media library using rename file API. This operation would rename all file versions of the file.
-
- Note: The old URLs will stop working. The file/file version URLs cached on CDN will continue to work unless a purge is requested.
-
-- `upload_files` (`write`): ImageKit.io allows you to upload files directly from both the server and client sides. For server-side uploads, private API key authentication is used. For client-side uploads, generate a one-time `token`, `signature`, and `expire` from your secure backend using private API. [Learn more](/docs/api-reference/upload-file/upload-file#how-to-implement-client-side-file-upload) about how to implement client-side file upload.
-
- The [V2 API](/docs/api-reference/upload-file/upload-file-v2) enhances security by verifying the entire payload using JWT.
-
- **File size limit** \
- On the free plan, the maximum upload file sizes are 20MB for images, audio, and raw files and 100MB for videos. On the paid plan, these limits increase to 40MB for images, audio, and raw files and 2GB for videos. These limits can be further increased with higher-tier plans.
-
- **Version limit** \
- A file can have a maximum of 100 versions.
-
- **Demo applications**
-
- - A full-fledged [upload widget using Uppy](https://github.com/imagekit-samples/uppy-uploader), supporting file selections from local storage, URL, Dropbox, Google Drive, Instagram, and more.
- - [Quick start guides](/docs/quick-start-guides) for various frameworks and technologies.
-
-### Resource `files.bulk`:
-
-- `delete_files_bulk` (`write`): This API deletes multiple files and all their file versions permanently.
-
- Note: If a file or specific transformation has been requested in the past, then the response is cached. Deleting a file does not purge the cache. You can purge the cache using purge cache API.
-
- A maximum of 100 files can be deleted at a time.
-
-- `add_tags_files_bulk` (`write`): This API adds tags to multiple files in bulk. A maximum of 50 files can be specified at a time.
-- `remove_ai_tags_files_bulk` (`write`): This API removes AITags from multiple files in bulk. A maximum of 50 files can be specified at a time.
-- `remove_tags_files_bulk` (`write`): This API removes tags from multiple files in bulk. A maximum of 50 files can be specified at a time.
-
-### Resource `files.versions`:
-
-- `list_files_versions` (`read`): This API returns details of all versions of a file.
-- `delete_files_versions` (`write`): This API deletes a non-current file version permanently. The API returns an empty response.
-
- Note: If you want to delete all versions of a file, use the delete file API.
-
-- `get_files_versions` (`read`): This API returns an object with details or attributes of a file version.
-- `restore_files_versions` (`write`): This API restores a file version as the current file version.
-
-### Resource `files.metadata`:
-
-- `get_files_metadata` (`read`): You can programmatically get image EXIF, pHash, and other metadata for uploaded files in the ImageKit.io media library using this API.
-
- You can also get the metadata in upload API response by passing `metadata` in `responseFields` parameter.
-
-- `get_from_url_files_metadata` (`read`): Get image EXIF, pHash, and other metadata from ImageKit.io powered remote URL using this API.
-
-### Resource `assets`:
-
-- `list_assets` (`read`): This API can list all the uploaded files and folders in your ImageKit.io media library. In addition, you can fine-tune your query by specifying various filters by generating a query string in a Lucene-like syntax and provide this generated string as the value of the `searchQuery`.
-
-### Resource `cache.invalidation`:
-
-- `create_cache_invalidation` (`write`): This API will purge CDN cache and ImageKit.io's internal cache for a file. Note: Purge cache is an asynchronous process and it may take some time to reflect the changes.
-- `get_cache_invalidation` (`read`): This API returns the status of a purge cache request.
-
-### Resource `folders`:
-
-- `create_folders` (`write`): This will create a new folder. You can specify the folder name and location of the parent folder where this new folder should be created.
-- `delete_folders` (`write`): This will delete a folder and all its contents permanently. The API returns an empty response.
-- `copy_folders` (`write`): This will copy one folder into another. The selected folder, its nested folders, files, and their versions (in `includeVersions` is set to true) are copied in this operation. Note: If any file at the destination has the same name as the source file, then the source file and its versions will be appended to the destination file version history.
-- `move_folders` (`write`): This will move one folder into another. The selected folder, its nested folders, files, and their versions are moved in this operation. Note: If any file at the destination has the same name as the source file, then the source file and its versions will be appended to the destination file version history.
-- `rename_folders` (`write`): This API allows you to rename an existing folder. The folder and all its nested assets and sub-folders will remain unchanged, but their paths will be updated to reflect the new folder name.
-
-### Resource `folders.job`:
-
-- `get_folders_job` (`read`): This API returns the status of a bulk job like copy and move folder operations.
-
-### Resource `accounts.usage`:
-
-- `get_accounts_usage` (`read`): Get the account usage information between two dates. Note that the API response includes data from the start date while excluding data from the end date. In other words, the data covers the period starting from the specified start date up to, but not including, the end date.
-
-### Resource `accounts.origins`:
-
-- `create_accounts_origins` (`write`): **Note:** This API is currently in beta.
- Creates a new origin and returns the origin object.
-- `update_accounts_origins` (`write`): **Note:** This API is currently in beta.
- Updates the origin identified by `id` and returns the updated origin object.
-- `list_accounts_origins` (`read`): **Note:** This API is currently in beta.
- Returns an array of all configured origins for the current account.
-- `delete_accounts_origins` (`write`): **Note:** This API is currently in beta.
- Permanently removes the origin identified by `id`. If the origin is in use by any URL‑endpoints, the API will return an error.
-- `get_accounts_origins` (`read`): **Note:** This API is currently in beta.
- Retrieves the origin identified by `id`.
-
-### Resource `accounts.urlEndpoints`:
-
-- `create_accounts_url_endpoints` (`write`): **Note:** This API is currently in beta.
- Creates a new URL‑endpoint and returns the resulting object.
-- `update_accounts_url_endpoints` (`write`): **Note:** This API is currently in beta.
- Updates the URL‑endpoint identified by `id` and returns the updated object.
-- `list_accounts_url_endpoints` (`read`): **Note:** This API is currently in beta.
- Returns an array of all URL‑endpoints configured including the default URL-endpoint generated by ImageKit during account creation.
-- `delete_accounts_url_endpoints` (`write`): **Note:** This API is currently in beta.
- Deletes the URL‑endpoint identified by `id`. You cannot delete the default URL‑endpoint created by ImageKit during account creation.
-- `get_accounts_url_endpoints` (`read`): **Note:** This API is currently in beta.
- Retrieves the URL‑endpoint identified by `id`.
-
-### Resource `beta.v2.files`:
-
-- `upload_v2_beta_files` (`write`): The V2 API enhances security by verifying the entire payload using JWT. This API is in beta.
-
- ImageKit.io allows you to upload files directly from both the server and client sides. For server-side uploads, private API key authentication is used. For client-side uploads, generate a one-time `token` from your secure backend using private API. [Learn more](/docs/api-reference/upload-file/upload-file-v2#how-to-implement-secure-client-side-file-upload) about how to implement secure client-side file upload.
-
- **File size limit** \
- On the free plan, the maximum upload file sizes are 20MB for images, audio, and raw files, and 100MB for videos. On the paid plan, these limits increase to 40MB for images, audio, and raw files, and 2GB for videos. These limits can be further increased with higher-tier plans.
-
- **Version limit** \
- A file can have a maximum of 100 versions.
-
- **Demo applications**
-
- - A full-fledged [upload widget using Uppy](https://github.com/imagekit-samples/uppy-uploader), supporting file selections from local storage, URL, Dropbox, Google Drive, Instagram, and more.
- - [Quick start guides](/docs/quick-start-guides) for various frameworks and technologies.
diff --git a/packages/mcp-server/cloudflare-worker/package.json b/packages/mcp-server/cloudflare-worker/package.json
index 85f7956d..1067db1d 100644
--- a/packages/mcp-server/cloudflare-worker/package.json
+++ b/packages/mcp-server/cloudflare-worker/package.json
@@ -18,7 +18,7 @@
},
"dependencies": {
"@cloudflare/workers-oauth-provider": "^0.0.5",
- "@modelcontextprotocol/sdk": "^1.11.4",
+ "@modelcontextprotocol/sdk": "^1.24.0",
"agents": "^0.0.88",
"hono": "^4.7.9",
"@imagekit/api-mcp": "latest",
diff --git a/packages/mcp-server/package.json b/packages/mcp-server/package.json
index 572eee54..ec5e4337 100644
--- a/packages/mcp-server/package.json
+++ b/packages/mcp-server/package.json
@@ -1,6 +1,6 @@
{
"name": "@imagekit/api-mcp",
- "version": "7.1.1",
+ "version": "8.0.0",
"description": "The official MCP Server for the Image Kit API",
"author": "Image Kit ",
"types": "dist/index.d.ts",
@@ -32,12 +32,14 @@
"dependencies": {
"@imagekit/nodejs": "file:../../dist/",
"@cloudflare/cabidela": "^0.2.4",
- "@modelcontextprotocol/sdk": "^1.11.5",
+ "@modelcontextprotocol/sdk": "^1.24.0",
"@valtown/deno-http-worker": "^0.0.21",
"cors": "^2.8.5",
"express": "^5.1.0",
- "jq-web": "https://github.com/stainless-api/jq-web/releases/download/v0.8.6/jq-web.tar.gz",
+ "fuse.js": "^7.1.0",
+ "jq-web": "https://github.com/stainless-api/jq-web/releases/download/v0.8.8/jq-web.tar.gz",
"qs": "^6.14.0",
+ "typescript": "5.8.3",
"yargs": "^17.7.2",
"zod": "^3.25.20",
"zod-to-json-schema": "^3.24.5",
@@ -47,7 +49,7 @@
"mcp-server": "dist/index.js"
},
"devDependencies": {
- "@anthropic-ai/mcpb": "^1.1.0",
+ "@anthropic-ai/mcpb": "1.1.0",
"@types/cors": "^2.8.19",
"@types/express": "^5.0.3",
"@types/jest": "^29.4.0",
@@ -64,8 +66,7 @@
"ts-morph": "^19.0.0",
"ts-node": "^10.5.0",
"tsc-multi": "https://github.com/stainless-api/tsc-multi/releases/download/v1.1.9/tsc-multi.tgz",
- "tsconfig-paths": "^4.0.0",
- "typescript": "5.8.3"
+ "tsconfig-paths": "^4.0.0"
},
"imports": {
"@imagekit/api-mcp": ".",
diff --git a/packages/mcp-server/src/code-tool-paths.cts b/packages/mcp-server/src/code-tool-paths.cts
deleted file mode 100644
index 15ce7f55..00000000
--- a/packages/mcp-server/src/code-tool-paths.cts
+++ /dev/null
@@ -1,3 +0,0 @@
-// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
-
-export const workerPath = require.resolve('./code-tool-worker.mjs');
diff --git a/packages/mcp-server/src/code-tool-types.ts b/packages/mcp-server/src/code-tool-types.ts
index 02e7e890..d3906768 100644
--- a/packages/mcp-server/src/code-tool-types.ts
+++ b/packages/mcp-server/src/code-tool-types.ts
@@ -11,4 +11,8 @@ export type WorkerSuccess = {
logLines: string[];
errLines: string[];
};
-export type WorkerError = { message: string | undefined };
+export type WorkerError = {
+ message: string | undefined;
+ logLines: string[];
+ errLines: string[];
+};
diff --git a/packages/mcp-server/src/code-tool-worker.ts b/packages/mcp-server/src/code-tool-worker.ts
deleted file mode 100644
index 865c3928..00000000
--- a/packages/mcp-server/src/code-tool-worker.ts
+++ /dev/null
@@ -1,46 +0,0 @@
-// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
-
-import util from 'node:util';
-import { WorkerInput, WorkerSuccess, WorkerError } from './code-tool-types';
-import { ImageKit } from '@imagekit/nodejs';
-
-const fetch = async (req: Request): Promise => {
- const { opts, code } = (await req.json()) as WorkerInput;
- const client = new ImageKit({
- ...opts,
- });
-
- const logLines: string[] = [];
- const errLines: string[] = [];
- const console = {
- log: (...args: unknown[]) => {
- logLines.push(util.format(...args));
- },
- error: (...args: unknown[]) => {
- errLines.push(util.format(...args));
- },
- };
- try {
- let run_ = async (client: any) => {};
- eval(`
- ${code}
- run_ = run;
- `);
- const result = await run_(client);
- return Response.json({
- result,
- logLines,
- errLines,
- } satisfies WorkerSuccess);
- } catch (e) {
- const message = e instanceof Error ? e.message : undefined;
- return Response.json(
- {
- message,
- } satisfies WorkerError,
- { status: 400, statusText: 'Code execution error' },
- );
- }
-};
-
-export default { fetch };
diff --git a/packages/mcp-server/src/code-tool.ts b/packages/mcp-server/src/code-tool.ts
index 47d2064a..676cb460 100644
--- a/packages/mcp-server/src/code-tool.ts
+++ b/packages/mcp-server/src/code-tool.ts
@@ -1,147 +1,63 @@
// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
-import { dirname } from 'node:path';
-import { pathToFileURL } from 'node:url';
-import ImageKit, { ClientOptions } from '@imagekit/nodejs';
-import { Endpoint, ContentBlock, Metadata } from './tools/types';
-
+import { McpTool, Metadata, ToolCallResult, asTextContentResult } from './types';
import { Tool } from '@modelcontextprotocol/sdk/types.js';
-
-import { WorkerInput, WorkerError, WorkerSuccess } from './code-tool-types';
-
+import { readEnv } from './server';
+import { WorkerSuccess } from './code-tool-types';
/**
* A tool that runs code against a copy of the SDK.
*
- * Instead of exposing every endpoint as it's own tool, which uses up too many tokens for LLMs to use at once,
+ * Instead of exposing every endpoint as its own tool, which uses up too many tokens for LLMs to use at once,
* we expose a single tool that can be used to search for endpoints by name, resource, operation, or tag, and then
* a generic endpoint that can be used to invoke any endpoint with the provided arguments.
*
* @param endpoints - The endpoints to include in the list.
*/
-export async function codeTool(): Promise {
+export function codeTool(): McpTool {
const metadata: Metadata = { resource: 'all', operation: 'write', tags: [] };
const tool: Tool = {
name: 'execute',
description:
- 'Runs Typescript code to interact with the API.\nYou are a skilled programmer writing code to interface with the service.\nDefine an async function named "run" that takes a single parameter of an initialized client, and it will be run.\nDo not initialize a client, but instead use the client that you are given as a parameter.\nYou will be returned anything that your function returns, plus the results of any console.log statements.\nIf any code triggers an error, the tool will return an error response, so you do not need to add error handling unless you want to output something more helpful than the raw error.\nIt is not necessary to add comments to code, unless by adding those comments you believe that you can generate better code.\nThis code will run in a container, and you will not be able to use fetch or otherwise interact with the network calls other than through the client you are given.\nAny variables you define won\'t live between successive uses of this call, so make sure to return or log any data you might need later.',
+ 'Runs JavaScript code to interact with the API.\n\nYou are a skilled programmer writing code to interface with the service.\nDefine an async function named "run" that takes a single parameter of an initialized SDK client and it will be run.\nWrite code within this template:\n\n```\nasync function run(client) {\n // Fill this out\n}\n```\n\nYou will be returned anything that your function returns, plus the results of any console.log statements.\nIf any code triggers an error, the tool will return an error response, so you do not need to add error handling unless you want to output something more helpful than the raw error.\nIt is not necessary to add comments to code, unless by adding those comments you believe that you can generate better code.\nThis code will run in a container, and you will not be able to use fetch or otherwise interact with the network calls other than through the client you are given.\nAny variables you define won\'t live between successive uses of this call, so make sure to return or log any data you might need later.',
inputSchema: { type: 'object', properties: { code: { type: 'string' } } },
};
+ const handler = async (_: unknown, args: any): Promise => {
+ const code = args.code as string;
- // Import dynamically to avoid failing at import time in cases where the environment is not well-supported.
- const { newDenoHTTPWorker } = await import('@valtown/deno-http-worker');
- const { workerPath } = await import('./code-tool-paths.cjs');
+ // this is not required, but passing a Stainless API key for the matching project_name
+ // will allow you to run code-mode queries against non-published versions of your SDK.
+ const stainlessAPIKey = readEnv('STAINLESS_API_KEY');
+ const codeModeEndpoint =
+ readEnv('CODE_MODE_ENDPOINT_URL') ?? 'https://api.stainless.com/api/ai/code-tool';
- const handler = async (client: ImageKit, args: unknown) => {
- const baseURLHostname = new URL(client.baseURL).hostname;
- const { code } = args as { code: string };
-
- const worker = await newDenoHTTPWorker(pathToFileURL(workerPath), {
- runFlags: [
- `--node-modules-dir=manual`,
- `--allow-read=code-tool-worker.mjs,${workerPath.replace(/([\/\\]node_modules)[\/\\].+$/, '$1')}/`,
- `--allow-net=${baseURLHostname}`,
- // Allow environment variables because instantiating the client will try to read from them,
- // even though they are not set.
- '--allow-env',
- ],
- printOutput: true,
- spawnOptions: {
- cwd: dirname(workerPath),
+ const res = await fetch(codeModeEndpoint, {
+ method: 'POST',
+ headers: {
+ ...(stainlessAPIKey && { Authorization: stainlessAPIKey }),
+ 'Content-Type': 'application/json',
+ client_envs: JSON.stringify({
+ IMAGEKIT_PRIVATE_KEY: readEnv('IMAGEKIT_PRIVATE_KEY'),
+ OPTIONAL_IMAGEKIT_IGNORES_THIS: readEnv('OPTIONAL_IMAGEKIT_IGNORES_THIS'),
+ IMAGEKIT_WEBHOOK_SECRET: readEnv('IMAGEKIT_WEBHOOK_SECRET'),
+ IMAGE_KIT_BASE_URL: readEnv('IMAGE_KIT_BASE_URL'),
+ }),
},
+ body: JSON.stringify({
+ project_name: 'imagekit',
+ client_opts: {},
+ code,
+ }),
});
- try {
- const resp = await new Promise((resolve, reject) => {
- worker.addEventListener('exit', (exitCode) => {
- reject(new Error(`Worker exited with code ${exitCode}`));
- });
-
- const opts: ClientOptions = {
- baseURL: client.baseURL,
- privateKey: client.privateKey,
- password: client.password,
- webhookSecret: client.webhookSecret,
- defaultHeaders: {
- 'X-Stainless-MCP': 'true',
- },
- };
-
- const req = worker.request(
- 'http://localhost',
- {
- headers: {
- 'content-type': 'application/json',
- },
- method: 'POST',
- },
- (resp) => {
- const body: Uint8Array[] = [];
- resp.on('error', (err) => {
- reject(err);
- });
- resp.on('data', (chunk) => {
- body.push(chunk);
- });
- resp.on('end', () => {
- resolve(
- new Response(Buffer.concat(body).toString(), {
- status: resp.statusCode ?? 200,
- headers: resp.headers as any,
- }),
- );
- });
- },
- );
-
- const body = JSON.stringify({
- opts,
- code,
- } satisfies WorkerInput);
-
- req.write(body, (err) => {
- if (err !== null && err !== undefined) {
- reject(err);
- }
- });
-
- req.end();
- });
-
- if (resp.status === 200) {
- const { result, logLines, errLines } = (await resp.json()) as WorkerSuccess;
- const returnOutput: ContentBlock | null =
- result === null ? null
- : result === undefined ? null
- : {
- type: 'text',
- text: typeof result === 'string' ? (result as string) : JSON.stringify(result),
- };
- const logOutput: ContentBlock | null =
- logLines.length === 0 ?
- null
- : {
- type: 'text',
- text: logLines.join('\n'),
- };
- const errOutput: ContentBlock | null =
- errLines.length === 0 ?
- null
- : {
- type: 'text',
- text: 'Error output:\n' + errLines.join('\n'),
- };
- return {
- content: [returnOutput, logOutput, errOutput].filter((block) => block !== null),
- };
- } else {
- const { message } = (await resp.json()) as WorkerError;
- throw new Error(message);
- }
- } catch (e) {
- throw e;
- } finally {
- worker.terminate();
+ if (!res.ok) {
+ throw new Error(
+ `${res.status}: ${
+ res.statusText
+ } error when trying to contact Code Tool server. Details: ${await res.text()}`,
+ );
}
+
+ return asTextContentResult((await res.json()) as WorkerSuccess);
};
return { metadata, tool, handler };
diff --git a/packages/mcp-server/src/compat.ts b/packages/mcp-server/src/compat.ts
deleted file mode 100644
index f84053c7..00000000
--- a/packages/mcp-server/src/compat.ts
+++ /dev/null
@@ -1,483 +0,0 @@
-import { Tool } from '@modelcontextprotocol/sdk/types.js';
-import { z } from 'zod';
-import { Endpoint } from './tools';
-
-export interface ClientCapabilities {
- topLevelUnions: boolean;
- validJson: boolean;
- refs: boolean;
- unions: boolean;
- formats: boolean;
- toolNameLength: number | undefined;
-}
-
-export const defaultClientCapabilities: ClientCapabilities = {
- topLevelUnions: true,
- validJson: true,
- refs: true,
- unions: true,
- formats: true,
- toolNameLength: undefined,
-};
-
-export const ClientType = z.enum(['openai-agents', 'claude', 'claude-code', 'cursor', 'infer']);
-export type ClientType = z.infer;
-
-// Client presets for compatibility
-// Note that these could change over time as models get better, so this is
-// a best effort.
-export const knownClients: Record, ClientCapabilities> = {
- 'openai-agents': {
- topLevelUnions: false,
- validJson: true,
- refs: true,
- unions: true,
- formats: true,
- toolNameLength: undefined,
- },
- claude: {
- topLevelUnions: true,
- validJson: false,
- refs: true,
- unions: true,
- formats: true,
- toolNameLength: undefined,
- },
- 'claude-code': {
- topLevelUnions: false,
- validJson: true,
- refs: true,
- unions: true,
- formats: true,
- toolNameLength: undefined,
- },
- cursor: {
- topLevelUnions: false,
- validJson: true,
- refs: false,
- unions: false,
- formats: false,
- toolNameLength: 50,
- },
-};
-
-/**
- * Attempts to parse strings into JSON objects
- */
-export function parseEmbeddedJSON(args: Record, schema: Record) {
- let updated = false;
- const newArgs: Record = Object.assign({}, args);
-
- for (const [key, value] of Object.entries(newArgs)) {
- if (typeof value === 'string') {
- try {
- const parsed = JSON.parse(value);
- // Only parse if result is a plain object (not array, null, or primitive)
- if (parsed && typeof parsed === 'object' && !Array.isArray(parsed)) {
- newArgs[key] = parsed;
- updated = true;
- }
- } catch (e) {
- // Not valid JSON, leave as is
- }
- }
- }
-
- if (updated) {
- return newArgs;
- }
-
- return args;
-}
-
-export type JSONSchema = {
- type?: string;
- properties?: Record;
- required?: string[];
- anyOf?: JSONSchema[];
- $ref?: string;
- $defs?: Record;
- [key: string]: any;
-};
-
-/**
- * Truncates tool names to the specified length while ensuring uniqueness.
- * If truncation would cause duplicate names, appends a number to make them unique.
- */
-export function truncateToolNames(names: string[], maxLength: number): Map {
- if (maxLength <= 0) {
- return new Map();
- }
-
- const renameMap = new Map();
- const usedNames = new Set();
-
- const toTruncate = names.filter((name) => name.length > maxLength);
-
- if (toTruncate.length === 0) {
- return renameMap;
- }
-
- const willCollide =
- new Set(toTruncate.map((name) => name.slice(0, maxLength - 1))).size < toTruncate.length;
-
- if (!willCollide) {
- for (const name of toTruncate) {
- const truncatedName = name.slice(0, maxLength);
- renameMap.set(name, truncatedName);
- }
- } else {
- const baseLength = maxLength - 1;
-
- for (const name of toTruncate) {
- const baseName = name.slice(0, baseLength);
- let counter = 1;
-
- while (usedNames.has(baseName + counter)) {
- counter++;
- }
-
- const finalName = baseName + counter;
- renameMap.set(name, finalName);
- usedNames.add(finalName);
- }
- }
-
- return renameMap;
-}
-
-/**
- * Removes top-level unions from a tool by splitting it into multiple tools,
- * one for each variant in the union.
- */
-export function removeTopLevelUnions(tool: Tool): Tool[] {
- const inputSchema = tool.inputSchema as JSONSchema;
- const variants = inputSchema.anyOf;
-
- if (!variants || !Array.isArray(variants) || variants.length === 0) {
- return [tool];
- }
-
- const defs = inputSchema.$defs || {};
-
- return variants.map((variant, index) => {
- const variantSchema: JSONSchema = {
- ...inputSchema,
- ...variant,
- type: 'object',
- properties: {
- ...(inputSchema.properties || {}),
- ...(variant.properties || {}),
- },
- };
-
- delete variantSchema.anyOf;
-
- if (!variantSchema['description']) {
- variantSchema['description'] = tool.description;
- }
-
- const usedDefs = findUsedDefs(variant, defs);
- if (Object.keys(usedDefs).length > 0) {
- variantSchema.$defs = usedDefs;
- } else {
- delete variantSchema.$defs;
- }
-
- return {
- ...tool,
- name: `${tool.name}_${toSnakeCase(variant['title'] || `variant${index + 1}`)}`,
- description: variant['description'] || tool.description,
- inputSchema: variantSchema,
- } as Tool;
- });
-}
-
-function findUsedDefs(
- schema: JSONSchema,
- defs: Record,
- visited: Set = new Set(),
-): Record {
- const usedDefs: Record = {};
-
- if (typeof schema !== 'object' || schema === null) {
- return usedDefs;
- }
-
- if (schema.$ref) {
- const refParts = schema.$ref.split('/');
- if (refParts[0] === '#' && refParts[1] === '$defs' && refParts[2]) {
- const defName = refParts[2];
- const def = defs[defName];
- if (def && !visited.has(schema.$ref)) {
- usedDefs[defName] = def;
- visited.add(schema.$ref);
- Object.assign(usedDefs, findUsedDefs(def, defs, visited));
- visited.delete(schema.$ref);
- }
- }
- return usedDefs;
- }
-
- for (const key in schema) {
- if (key !== '$defs' && typeof schema[key] === 'object' && schema[key] !== null) {
- Object.assign(usedDefs, findUsedDefs(schema[key] as JSONSchema, defs, visited));
- }
- }
-
- return usedDefs;
-}
-
-// Export for testing
-export { findUsedDefs };
-
-/**
- * Inlines all $refs in a schema, eliminating $defs.
- * If a circular reference is detected, the circular property is removed.
- */
-export function inlineRefs(schema: JSONSchema): JSONSchema {
- if (!schema || typeof schema !== 'object') {
- return schema;
- }
-
- const clonedSchema = { ...schema };
- const defs: Record = schema.$defs || {};
-
- delete clonedSchema.$defs;
-
- const result = inlineRefsRecursive(clonedSchema, defs, new Set());
- // The top level can never be null
- return result === null ? {} : result;
-}
-
-function inlineRefsRecursive(
- schema: JSONSchema,
- defs: Record,
- refPath: Set,
-): JSONSchema | null {
- if (!schema || typeof schema !== 'object') {
- return schema;
- }
-
- if (Array.isArray(schema)) {
- return schema.map((item) => {
- const processed = inlineRefsRecursive(item, defs, refPath);
- return processed === null ? {} : processed;
- }) as JSONSchema;
- }
-
- const result = { ...schema };
-
- if ('$ref' in result && typeof result.$ref === 'string') {
- if (result.$ref.startsWith('#/$defs/')) {
- const refName = result.$ref.split('/').pop() as string;
- const def = defs[refName];
-
- // If we've already seen this ref in our path, we have a circular reference
- if (refPath.has(result.$ref)) {
- // For circular references, we completely remove the property
- // by returning null. The parent will remove it.
- return null;
- }
-
- if (def) {
- const newRefPath = new Set(refPath);
- newRefPath.add(result.$ref);
-
- const inlinedDef = inlineRefsRecursive({ ...def }, defs, newRefPath);
-
- if (inlinedDef === null) {
- return { ...result };
- }
-
- // Merge the inlined definition with the original schema's properties
- // but preserve things like description, etc.
- const { $ref, ...rest } = result;
- return { ...inlinedDef, ...rest };
- }
- }
-
- // Keep external refs as-is
- return result;
- }
-
- for (const key in result) {
- if (result[key] && typeof result[key] === 'object') {
- const processed = inlineRefsRecursive(result[key] as JSONSchema, defs, refPath);
- if (processed === null) {
- // Remove properties that would cause circular references
- delete result[key];
- } else {
- result[key] = processed;
- }
- }
- }
-
- return result;
-}
-
-/**
- * Removes anyOf fields from a schema, using only the first variant.
- */
-export function removeAnyOf(schema: JSONSchema): JSONSchema {
- if (!schema || typeof schema !== 'object') {
- return schema;
- }
-
- if (Array.isArray(schema)) {
- return schema.map((item) => removeAnyOf(item)) as JSONSchema;
- }
-
- const result = { ...schema };
-
- if ('anyOf' in result && Array.isArray(result.anyOf) && result.anyOf.length > 0) {
- const firstVariant = result.anyOf[0];
-
- if (firstVariant && typeof firstVariant === 'object') {
- // Special handling for properties to ensure deep merge
- if (firstVariant.properties && result.properties) {
- result.properties = {
- ...result.properties,
- ...(firstVariant.properties as Record),
- };
- } else if (firstVariant.properties) {
- result.properties = { ...firstVariant.properties };
- }
-
- for (const key in firstVariant) {
- if (key !== 'properties') {
- result[key] = firstVariant[key];
- }
- }
- }
-
- delete result.anyOf;
- }
-
- for (const key in result) {
- if (result[key] && typeof result[key] === 'object') {
- result[key] = removeAnyOf(result[key] as JSONSchema);
- }
- }
-
- return result;
-}
-
-/**
- * Removes format fields from a schema and appends them to the description.
- */
-export function removeFormats(schema: JSONSchema, formatsCapability: boolean): JSONSchema {
- if (formatsCapability) {
- return schema;
- }
-
- if (!schema || typeof schema !== 'object') {
- return schema;
- }
-
- if (Array.isArray(schema)) {
- return schema.map((item) => removeFormats(item, formatsCapability)) as JSONSchema;
- }
-
- const result = { ...schema };
-
- if ('format' in result && typeof result['format'] === 'string') {
- const formatStr = `(format: "${result['format']}")`;
-
- if ('description' in result && typeof result['description'] === 'string') {
- result['description'] = `${result['description']} ${formatStr}`;
- } else {
- result['description'] = formatStr;
- }
-
- delete result['format'];
- }
-
- for (const key in result) {
- if (result[key] && typeof result[key] === 'object') {
- result[key] = removeFormats(result[key] as JSONSchema, formatsCapability);
- }
- }
-
- return result;
-}
-
-/**
- * Applies all compatibility transformations to the endpoints based on the provided capabilities.
- */
-export function applyCompatibilityTransformations(
- endpoints: Endpoint[],
- capabilities: ClientCapabilities,
-): Endpoint[] {
- let transformedEndpoints = [...endpoints];
-
- // Handle top-level unions first as this changes tool names
- if (!capabilities.topLevelUnions) {
- const newEndpoints: Endpoint[] = [];
-
- for (const endpoint of transformedEndpoints) {
- const variantTools = removeTopLevelUnions(endpoint.tool);
-
- if (variantTools.length === 1) {
- newEndpoints.push(endpoint);
- } else {
- for (const variantTool of variantTools) {
- newEndpoints.push({
- ...endpoint,
- tool: variantTool,
- });
- }
- }
- }
-
- transformedEndpoints = newEndpoints;
- }
-
- if (capabilities.toolNameLength) {
- const toolNames = transformedEndpoints.map((endpoint) => endpoint.tool.name);
- const renameMap = truncateToolNames(toolNames, capabilities.toolNameLength);
-
- transformedEndpoints = transformedEndpoints.map((endpoint) => ({
- ...endpoint,
- tool: {
- ...endpoint.tool,
- name: renameMap.get(endpoint.tool.name) ?? endpoint.tool.name,
- },
- }));
- }
-
- if (!capabilities.refs || !capabilities.unions || !capabilities.formats) {
- transformedEndpoints = transformedEndpoints.map((endpoint) => {
- let schema = endpoint.tool.inputSchema as JSONSchema;
-
- if (!capabilities.refs) {
- schema = inlineRefs(schema);
- }
-
- if (!capabilities.unions) {
- schema = removeAnyOf(schema);
- }
-
- if (!capabilities.formats) {
- schema = removeFormats(schema, capabilities.formats);
- }
-
- return {
- ...endpoint,
- tool: {
- ...endpoint.tool,
- inputSchema: schema as typeof endpoint.tool.inputSchema,
- },
- };
- });
- }
-
- return transformedEndpoints;
-}
-
-function toSnakeCase(str: string): string {
- return str
- .replace(/\s+/g, '_')
- .replace(/([a-z])([A-Z])/g, '$1_$2')
- .toLowerCase();
-}
diff --git a/packages/mcp-server/src/docs-search-tool.ts b/packages/mcp-server/src/docs-search-tool.ts
index f05cd9b2..9af38ab5 100644
--- a/packages/mcp-server/src/docs-search-tool.ts
+++ b/packages/mcp-server/src/docs-search-tool.ts
@@ -1,6 +1,6 @@
// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
-import { Metadata, asTextContentResult } from './tools/types';
+import { Metadata, asTextContentResult } from './types';
import { Tool } from '@modelcontextprotocol/sdk/types.js';
@@ -13,8 +13,7 @@ export const metadata: Metadata = {
export const tool: Tool = {
name: 'search_docs',
- description:
- 'Search for documentation for how to use the client to interact with the API.\nThe tool will return an array of Markdown-formatted documentation pages.',
+ description: 'Search for documentation for how to use the client to interact with the API.',
inputSchema: {
type: 'object',
properties: {
@@ -25,7 +24,12 @@ export const tool: Tool = {
language: {
type: 'string',
description: 'The language for the SDK to search for.',
- enum: ['http', 'python', 'go', 'typescript', 'terraform', 'ruby', 'java', 'kotlin'],
+ enum: ['http', 'python', 'go', 'typescript', 'javascript', 'terraform', 'ruby', 'java', 'kotlin'],
+ },
+ detail: {
+ type: 'string',
+ description: 'The amount of detail to return.',
+ enum: ['default', 'verbose'],
},
},
required: ['query', 'language'],
@@ -42,6 +46,13 @@ export const handler = async (_: unknown, args: Record | undefi
const body = args as any;
const query = new URLSearchParams(body).toString();
const result = await fetch(`${docsSearchURL}?${query}`);
+
+ if (!result.ok) {
+ throw new Error(
+ `${result.status}: ${result.statusText} when using doc search tool. Details: ${await result.text()}`,
+ );
+ }
+
return asTextContentResult(await result.json());
};
diff --git a/packages/mcp-server/src/dynamic-tools.ts b/packages/mcp-server/src/dynamic-tools.ts
deleted file mode 100644
index 47d60e0d..00000000
--- a/packages/mcp-server/src/dynamic-tools.ts
+++ /dev/null
@@ -1,153 +0,0 @@
-import ImageKit from '@imagekit/nodejs';
-import { Endpoint, asTextContentResult, ToolCallResult } from './tools/types';
-import { zodToJsonSchema } from 'zod-to-json-schema';
-import { z } from 'zod';
-import { Cabidela } from '@cloudflare/cabidela';
-
-function zodToInputSchema(schema: z.ZodSchema) {
- return {
- type: 'object' as const,
- ...(zodToJsonSchema(schema) as any),
- };
-}
-
-/**
- * A list of tools that expose all the endpoints in the API dynamically.
- *
- * Instead of exposing every endpoint as it's own tool, which uses up too many tokens for LLMs to use at once,
- * we expose a single tool that can be used to search for endpoints by name, resource, operation, or tag, and then
- * a generic endpoint that can be used to invoke any endpoint with the provided arguments.
- *
- * @param endpoints - The endpoints to include in the list.
- */
-export function dynamicTools(endpoints: Endpoint[]): Endpoint[] {
- const listEndpointsSchema = z.object({
- search_query: z
- .string()
- .optional()
- .describe(
- 'An optional search query to filter the endpoints by. Provide a partial name, resource, operation, or tag to filter the endpoints returned.',
- ),
- });
-
- const listEndpointsTool = {
- metadata: {
- resource: 'dynamic_tools',
- operation: 'read' as const,
- tags: [],
- },
- tool: {
- name: 'list_api_endpoints',
- description: 'List or search for all endpoints in the Image Kit TypeScript API',
- inputSchema: zodToInputSchema(listEndpointsSchema),
- },
- handler: async (client: ImageKit, args: Record | undefined): Promise => {
- const query = args && listEndpointsSchema.parse(args).search_query?.trim();
-
- const filteredEndpoints =
- query && query.length > 0 ?
- endpoints.filter((endpoint) => {
- const fieldsToMatch = [
- endpoint.tool.name,
- endpoint.tool.description,
- endpoint.metadata.resource,
- endpoint.metadata.operation,
- ...endpoint.metadata.tags,
- ];
- return fieldsToMatch.some((field) => field && field.toLowerCase().includes(query.toLowerCase()));
- })
- : endpoints;
-
- return asTextContentResult({
- tools: filteredEndpoints.map(({ tool, metadata }) => ({
- name: tool.name,
- description: tool.description,
- resource: metadata.resource,
- operation: metadata.operation,
- tags: metadata.tags,
- })),
- });
- },
- };
-
- const getEndpointSchema = z.object({
- endpoint: z.string().describe('The name of the endpoint to get the schema for.'),
- });
- const getEndpointTool = {
- metadata: {
- resource: 'dynamic_tools',
- operation: 'read' as const,
- tags: [],
- },
- tool: {
- name: 'get_api_endpoint_schema',
- description:
- 'Get the schema for an endpoint in the Image Kit TypeScript API. You can use the schema returned by this tool to invoke an endpoint with the `invoke_api_endpoint` tool.',
- inputSchema: zodToInputSchema(getEndpointSchema),
- },
- handler: async (client: ImageKit, args: Record | undefined) => {
- if (!args) {
- throw new Error('No endpoint provided');
- }
- const endpointName = getEndpointSchema.parse(args).endpoint;
-
- const endpoint = endpoints.find((e) => e.tool.name === endpointName);
- if (!endpoint) {
- throw new Error(`Endpoint ${endpointName} not found`);
- }
- return asTextContentResult(endpoint.tool);
- },
- };
-
- const invokeEndpointSchema = z.object({
- endpoint_name: z.string().describe('The name of the endpoint to invoke.'),
- args: z
- .record(z.string(), z.any())
- .describe(
- 'The arguments to pass to the endpoint. This must match the schema returned by the `get_api_endpoint_schema` tool.',
- ),
- });
-
- const invokeEndpointTool = {
- metadata: {
- resource: 'dynamic_tools',
- operation: 'write' as const,
- tags: [],
- },
- tool: {
- name: 'invoke_api_endpoint',
- description:
- 'Invoke an endpoint in the Image Kit TypeScript API. Note: use the `list_api_endpoints` tool to get the list of endpoints and `get_api_endpoint_schema` tool to get the schema for an endpoint.',
- inputSchema: zodToInputSchema(invokeEndpointSchema),
- },
- handler: async (client: ImageKit, args: Record | undefined): Promise => {
- if (!args) {
- throw new Error('No endpoint provided');
- }
- const { success, data, error } = invokeEndpointSchema.safeParse(args);
- if (!success) {
- throw new Error(`Invalid arguments for endpoint. ${error?.format()}`);
- }
- const { endpoint_name, args: endpointArgs } = data;
-
- const endpoint = endpoints.find((e) => e.tool.name === endpoint_name);
- if (!endpoint) {
- throw new Error(
- `Endpoint ${endpoint_name} not found. Use the \`list_api_endpoints\` tool to get the list of available endpoints.`,
- );
- }
-
- try {
- // Try to validate the arguments for a better error message
- const cabidela = new Cabidela(endpoint.tool.inputSchema, { fullErrors: true });
- cabidela.validate(endpointArgs);
- } catch (error) {
- throw new Error(`Invalid arguments for endpoint ${endpoint_name}:\n${error}`);
- }
-
- return await endpoint.handler(client, endpointArgs);
- },
- };
-
- return [getEndpointTool, listEndpointsTool, invokeEndpointTool];
-}
diff --git a/packages/mcp-server/src/filtering.ts b/packages/mcp-server/src/filtering.ts
deleted file mode 100644
index 1aa9a40c..00000000
--- a/packages/mcp-server/src/filtering.ts
+++ /dev/null
@@ -1,14 +0,0 @@
-// @ts-nocheck
-import initJq from 'jq-web';
-
-export async function maybeFilter(jqFilter: unknown | undefined, response: any): Promise {
- if (jqFilter && typeof jqFilter === 'string') {
- return await jq(response, jqFilter);
- } else {
- return response;
- }
-}
-
-async function jq(json: any, jqFilter: string) {
- return (await initJq).json(json, jqFilter);
-}
diff --git a/packages/mcp-server/src/headers.ts b/packages/mcp-server/src/headers.ts
index 63e3abc9..40fd3090 100644
--- a/packages/mcp-server/src/headers.ts
+++ b/packages/mcp-server/src/headers.ts
@@ -15,7 +15,9 @@ export const parseAuthHeaders = (req: IncomingMessage): Partial =
password: rawValue.slice(rawValue.search(':') + 1),
};
default:
- throw new Error(`Unsupported authorization scheme`);
+ throw new Error(
+ 'Unsupported authorization scheme. Expected the "Authorization" header to be a supported scheme (Basic).',
+ );
}
}
diff --git a/packages/mcp-server/src/http.ts b/packages/mcp-server/src/http.ts
index ec34ab47..2366d8f9 100644
--- a/packages/mcp-server/src/http.ts
+++ b/packages/mcp-server/src/http.ts
@@ -4,38 +4,21 @@ import { McpServer } from '@modelcontextprotocol/sdk/server/mcp';
import { StreamableHTTPServerTransport } from '@modelcontextprotocol/sdk/server/streamableHttp.js';
import express from 'express';
-import { fromError } from 'zod-validation-error/v3';
-import { McpOptions, parseQueryOptions } from './options';
+import { McpOptions } from './options';
import { ClientOptions, initMcpServer, newMcpServer } from './server';
import { parseAuthHeaders } from './headers';
const newServer = ({
clientOptions,
- mcpOptions: defaultMcpOptions,
req,
res,
}: {
clientOptions: ClientOptions;
- mcpOptions: McpOptions;
req: express.Request;
res: express.Response;
}): McpServer | null => {
const server = newMcpServer();
- let mcpOptions: McpOptions;
- try {
- mcpOptions = parseQueryOptions(defaultMcpOptions, req.query);
- } catch (error) {
- res.status(400).json({
- jsonrpc: '2.0',
- error: {
- code: -32000,
- message: `Invalid request: ${fromError(error)}`,
- },
- });
- return null;
- }
-
try {
const authOptions = parseAuthHeaders(req);
initMcpServer({
@@ -44,14 +27,13 @@ const newServer = ({
...clientOptions,
...authOptions,
},
- mcpOptions,
});
- } catch {
+ } catch (error) {
res.status(401).json({
jsonrpc: '2.0',
error: {
code: -32000,
- message: 'Unauthorized',
+ message: `Unauthorized: ${error instanceof Error ? error.message : error}`,
},
});
return null;
diff --git a/packages/mcp-server/src/index.ts b/packages/mcp-server/src/index.ts
index 4850a0e2..0f6dd426 100644
--- a/packages/mcp-server/src/index.ts
+++ b/packages/mcp-server/src/index.ts
@@ -1,20 +1,15 @@
#!/usr/bin/env node
import { selectTools } from './server';
-import { Endpoint, endpoints } from './tools';
import { McpOptions, parseCLIOptions } from './options';
import { launchStdioServer } from './stdio';
import { launchStreamableHTTPServer } from './http';
+import type { McpTool } from './types';
async function main() {
const options = parseOptionsOrError();
- if (options.list) {
- listAllTools();
- return;
- }
-
- const selectedTools = await selectToolsOrError(endpoints, options);
+ const selectedTools = await selectToolsOrError(options);
console.error(
`MCP Server starting with ${selectedTools.length} tools:`,
@@ -23,7 +18,7 @@ async function main() {
switch (options.transport) {
case 'stdio':
- await launchStdioServer(options);
+ await launchStdioServer();
break;
case 'http':
await launchStreamableHTTPServer(options, options.port ?? options.socket);
@@ -47,9 +42,9 @@ function parseOptionsOrError() {
}
}
-async function selectToolsOrError(endpoints: Endpoint[], options: McpOptions): Promise {
+async function selectToolsOrError(options: McpOptions): Promise {
try {
- const includedTools = await selectTools(endpoints, options);
+ const includedTools = selectTools(options);
if (includedTools.length === 0) {
console.error('No tools match the provided filters.');
process.exit(1);
@@ -64,45 +59,3 @@ async function selectToolsOrError(endpoints: Endpoint[], options: McpOptions): P
process.exit(1);
}
}
-
-function listAllTools() {
- if (endpoints.length === 0) {
- console.log('No tools available.');
- return;
- }
- console.log('Available tools:\n');
-
- // Group endpoints by resource
- const resourceGroups = new Map();
-
- for (const endpoint of endpoints) {
- const resource = endpoint.metadata.resource;
- if (!resourceGroups.has(resource)) {
- resourceGroups.set(resource, []);
- }
- resourceGroups.get(resource)!.push(endpoint);
- }
-
- // Sort resources alphabetically
- const sortedResources = Array.from(resourceGroups.keys()).sort();
-
- // Display hierarchically by resource
- for (const resource of sortedResources) {
- console.log(`Resource: ${resource}`);
-
- const resourceEndpoints = resourceGroups.get(resource)!;
- // Sort endpoints by tool name
- resourceEndpoints.sort((a, b) => a.tool.name.localeCompare(b.tool.name));
-
- for (const endpoint of resourceEndpoints) {
- const {
- tool,
- metadata: { operation, tags },
- } = endpoint;
-
- console.log(` - ${tool.name} (${operation}) ${tags.length > 0 ? `tags: ${tags.join(', ')}` : ''}`);
- console.log(` Description: ${tool.description}`);
- }
- console.log('');
- }
-}
diff --git a/packages/mcp-server/src/options.ts b/packages/mcp-server/src/options.ts
index 4fe3b987..6c8bb8d1 100644
--- a/packages/mcp-server/src/options.ts
+++ b/packages/mcp-server/src/options.ts
@@ -2,140 +2,31 @@ import qs from 'qs';
import yargs from 'yargs';
import { hideBin } from 'yargs/helpers';
import z from 'zod';
-import { endpoints, Filter } from './tools';
-import { ClientCapabilities, knownClients, ClientType } from './compat';
export type CLIOptions = McpOptions & {
- list: boolean;
transport: 'stdio' | 'http';
port: number | undefined;
socket: string | undefined;
};
export type McpOptions = {
- client?: ClientType | undefined;
- includeDynamicTools?: boolean | undefined;
- includeAllTools?: boolean | undefined;
- includeCodeTools?: boolean | undefined;
includeDocsTools?: boolean | undefined;
- filters?: Filter[] | undefined;
- capabilities?: Partial | undefined;
};
-const CAPABILITY_CHOICES = [
- 'top-level-unions',
- 'valid-json',
- 'refs',
- 'unions',
- 'formats',
- 'tool-name-length',
-] as const;
-
-type Capability = (typeof CAPABILITY_CHOICES)[number];
-
-function parseCapabilityValue(cap: string): { name: Capability; value?: number } {
- if (cap.startsWith('tool-name-length=')) {
- const parts = cap.split('=');
- if (parts.length === 2) {
- const length = parseInt(parts[1]!, 10);
- if (!isNaN(length)) {
- return { name: 'tool-name-length', value: length };
- }
- throw new Error(`Invalid tool-name-length value: ${parts[1]}. Expected a number.`);
- }
- throw new Error(`Invalid format for tool-name-length. Expected tool-name-length=N.`);
- }
- if (!CAPABILITY_CHOICES.includes(cap as Capability)) {
- throw new Error(`Unknown capability: ${cap}. Valid capabilities are: ${CAPABILITY_CHOICES.join(', ')}`);
- }
- return { name: cap as Capability };
-}
-
export function parseCLIOptions(): CLIOptions {
const opts = yargs(hideBin(process.argv))
.option('tools', {
type: 'string',
array: true,
- choices: ['dynamic', 'all', 'code', 'docs'],
+ choices: ['code', 'docs'],
description: 'Use dynamic tools or all tools',
})
.option('no-tools', {
type: 'string',
array: true,
- choices: ['dynamic', 'all', 'code', 'docs'],
+ choices: ['code', 'docs'],
description: 'Do not use any dynamic or all tools',
})
- .option('tool', {
- type: 'string',
- array: true,
- description: 'Include tools matching the specified names',
- })
- .option('resource', {
- type: 'string',
- array: true,
- description: 'Include tools matching the specified resources',
- })
- .option('operation', {
- type: 'string',
- array: true,
- choices: ['read', 'write'],
- description: 'Include tools matching the specified operations',
- })
- .option('tag', {
- type: 'string',
- array: true,
- description: 'Include tools with the specified tags',
- })
- .option('no-tool', {
- type: 'string',
- array: true,
- description: 'Exclude tools matching the specified names',
- })
- .option('no-resource', {
- type: 'string',
- array: true,
- description: 'Exclude tools matching the specified resources',
- })
- .option('no-operation', {
- type: 'string',
- array: true,
- description: 'Exclude tools matching the specified operations',
- })
- .option('no-tag', {
- type: 'string',
- array: true,
- description: 'Exclude tools with the specified tags',
- })
- .option('list', {
- type: 'boolean',
- description: 'List all tools and exit',
- })
- .option('client', {
- type: 'string',
- choices: Object.keys(knownClients),
- description: 'Specify the MCP client being used',
- })
- .option('capability', {
- type: 'string',
- array: true,
- description: 'Specify client capabilities',
- coerce: (values: string[]) => {
- return values.flatMap((v) => v.split(','));
- },
- })
- .option('no-capability', {
- type: 'string',
- array: true,
- description: 'Unset client capabilities',
- choices: CAPABILITY_CHOICES,
- coerce: (values: string[]) => {
- return values.flatMap((v) => v.split(','));
- },
- })
- .option('describe-capabilities', {
- type: 'boolean',
- description: 'Print detailed explanation of client capabilities and exit',
- })
.option('transport', {
type: 'string',
choices: ['stdio', 'http'],
@@ -152,122 +43,19 @@ export function parseCLIOptions(): CLIOptions {
})
.help();
- for (const [command, desc] of examples()) {
- opts.example(command, desc);
- }
-
const argv = opts.parseSync();
- // Handle describe-capabilities flag
- if (argv.describeCapabilities) {
- console.log(getCapabilitiesExplanation());
- process.exit(0);
- }
-
- const filters: Filter[] = [];
-
- // Helper function to support comma-separated values
- const splitValues = (values: string[] | undefined): string[] => {
- if (!values) return [];
- return values.flatMap((v) => v.split(','));
- };
-
- for (const tag of splitValues(argv.tag)) {
- filters.push({ type: 'tag', op: 'include', value: tag });
- }
-
- for (const tag of splitValues(argv.noTag)) {
- filters.push({ type: 'tag', op: 'exclude', value: tag });
- }
-
- for (const resource of splitValues(argv.resource)) {
- filters.push({ type: 'resource', op: 'include', value: resource });
- }
-
- for (const resource of splitValues(argv.noResource)) {
- filters.push({ type: 'resource', op: 'exclude', value: resource });
- }
-
- for (const tool of splitValues(argv.tool)) {
- filters.push({ type: 'tool', op: 'include', value: tool });
- }
-
- for (const tool of splitValues(argv.noTool)) {
- filters.push({ type: 'tool', op: 'exclude', value: tool });
- }
-
- for (const operation of splitValues(argv.operation)) {
- filters.push({ type: 'operation', op: 'include', value: operation });
- }
-
- for (const operation of splitValues(argv.noOperation)) {
- filters.push({ type: 'operation', op: 'exclude', value: operation });
- }
-
- // Parse client capabilities
- const clientCapabilities: Partial = {};
-
- // Apply individual capability overrides
- if (Array.isArray(argv.capability)) {
- for (const cap of argv.capability) {
- const parsedCap = parseCapabilityValue(cap);
- if (parsedCap.name === 'top-level-unions') {
- clientCapabilities.topLevelUnions = true;
- } else if (parsedCap.name === 'valid-json') {
- clientCapabilities.validJson = true;
- } else if (parsedCap.name === 'refs') {
- clientCapabilities.refs = true;
- } else if (parsedCap.name === 'unions') {
- clientCapabilities.unions = true;
- } else if (parsedCap.name === 'formats') {
- clientCapabilities.formats = true;
- } else if (parsedCap.name === 'tool-name-length') {
- clientCapabilities.toolNameLength = parsedCap.value;
- }
- }
- }
-
- // Handle no-capability options to unset capabilities
- if (Array.isArray(argv.noCapability)) {
- for (const cap of argv.noCapability) {
- if (cap === 'top-level-unions') {
- clientCapabilities.topLevelUnions = false;
- } else if (cap === 'valid-json') {
- clientCapabilities.validJson = false;
- } else if (cap === 'refs') {
- clientCapabilities.refs = false;
- } else if (cap === 'unions') {
- clientCapabilities.unions = false;
- } else if (cap === 'formats') {
- clientCapabilities.formats = false;
- } else if (cap === 'tool-name-length') {
- clientCapabilities.toolNameLength = undefined;
- }
- }
- }
-
- const shouldIncludeToolType = (toolType: 'dynamic' | 'all' | 'code' | 'docs') =>
+ const shouldIncludeToolType = (toolType: 'code' | 'docs') =>
argv.noTools?.includes(toolType) ? false
: argv.tools?.includes(toolType) ? true
: undefined;
- const includeDynamicTools = shouldIncludeToolType('dynamic');
- const includeAllTools = shouldIncludeToolType('all');
- const includeCodeTools = shouldIncludeToolType('code');
const includeDocsTools = shouldIncludeToolType('docs');
const transport = argv.transport as 'stdio' | 'http';
- const client = argv.client as ClientType;
return {
- client: client && client !== 'infer' && knownClients[client] ? client : undefined,
- includeDynamicTools,
- includeAllTools,
- includeCodeTools,
includeDocsTools,
- filters,
- capabilities: clientCapabilities,
- list: argv.list || false,
transport,
port: argv.port,
socket: argv.socket,
@@ -284,183 +72,21 @@ const coerceArray = (zodType: T) =>
);
const QueryOptions = z.object({
- tools: coerceArray(z.enum(['dynamic', 'all', 'docs'])).describe('Use dynamic tools or all tools'),
- no_tools: coerceArray(z.enum(['dynamic', 'all', 'docs'])).describe('Do not use dynamic tools or all tools'),
+ tools: coerceArray(z.enum(['code', 'docs'])).describe('Specify which MCP tools to use'),
+ no_tools: coerceArray(z.enum(['code', 'docs'])).describe('Specify which MCP tools to not use.'),
tool: coerceArray(z.string()).describe('Include tools matching the specified names'),
- resource: coerceArray(z.string()).describe('Include tools matching the specified resources'),
- operation: coerceArray(z.enum(['read', 'write'])).describe(
- 'Include tools matching the specified operations',
- ),
- tag: coerceArray(z.string()).describe('Include tools with the specified tags'),
- no_tool: coerceArray(z.string()).describe('Exclude tools matching the specified names'),
- no_resource: coerceArray(z.string()).describe('Exclude tools matching the specified resources'),
- no_operation: coerceArray(z.enum(['read', 'write'])).describe(
- 'Exclude tools matching the specified operations',
- ),
- no_tag: coerceArray(z.string()).describe('Exclude tools with the specified tags'),
- client: ClientType.optional().describe('Specify the MCP client being used'),
- capability: coerceArray(z.string()).describe('Specify client capabilities'),
- no_capability: coerceArray(z.enum(CAPABILITY_CHOICES)).describe('Unset client capabilities'),
});
export function parseQueryOptions(defaultOptions: McpOptions, query: unknown): McpOptions {
const queryObject = typeof query === 'string' ? qs.parse(query) : query;
const queryOptions = QueryOptions.parse(queryObject);
- const filters: Filter[] = [...(defaultOptions.filters ?? [])];
-
- for (const resource of queryOptions.resource || []) {
- filters.push({ type: 'resource', op: 'include', value: resource });
- }
- for (const operation of queryOptions.operation || []) {
- filters.push({ type: 'operation', op: 'include', value: operation });
- }
- for (const tag of queryOptions.tag || []) {
- filters.push({ type: 'tag', op: 'include', value: tag });
- }
- for (const tool of queryOptions.tool || []) {
- filters.push({ type: 'tool', op: 'include', value: tool });
- }
- for (const resource of queryOptions.no_resource || []) {
- filters.push({ type: 'resource', op: 'exclude', value: resource });
- }
- for (const operation of queryOptions.no_operation || []) {
- filters.push({ type: 'operation', op: 'exclude', value: operation });
- }
- for (const tag of queryOptions.no_tag || []) {
- filters.push({ type: 'tag', op: 'exclude', value: tag });
- }
- for (const tool of queryOptions.no_tool || []) {
- filters.push({ type: 'tool', op: 'exclude', value: tool });
- }
-
- // Parse client capabilities
- const clientCapabilities: Partial = { ...defaultOptions.capabilities };
-
- for (const cap of queryOptions.capability || []) {
- const parsed = parseCapabilityValue(cap);
- if (parsed.name === 'top-level-unions') {
- clientCapabilities.topLevelUnions = true;
- } else if (parsed.name === 'valid-json') {
- clientCapabilities.validJson = true;
- } else if (parsed.name === 'refs') {
- clientCapabilities.refs = true;
- } else if (parsed.name === 'unions') {
- clientCapabilities.unions = true;
- } else if (parsed.name === 'formats') {
- clientCapabilities.formats = true;
- } else if (parsed.name === 'tool-name-length') {
- clientCapabilities.toolNameLength = parsed.value;
- }
- }
-
- for (const cap of queryOptions.no_capability || []) {
- if (cap === 'top-level-unions') {
- clientCapabilities.topLevelUnions = false;
- } else if (cap === 'valid-json') {
- clientCapabilities.validJson = false;
- } else if (cap === 'refs') {
- clientCapabilities.refs = false;
- } else if (cap === 'unions') {
- clientCapabilities.unions = false;
- } else if (cap === 'formats') {
- clientCapabilities.formats = false;
- } else if (cap === 'tool-name-length') {
- clientCapabilities.toolNameLength = undefined;
- }
- }
-
- let dynamicTools: boolean | undefined =
- queryOptions.no_tools && queryOptions.no_tools?.includes('dynamic') ? false
- : queryOptions.tools?.includes('dynamic') ? true
- : defaultOptions.includeDynamicTools;
-
- let allTools: boolean | undefined =
- queryOptions.no_tools && queryOptions.no_tools?.includes('all') ? false
- : queryOptions.tools?.includes('all') ? true
- : defaultOptions.includeAllTools;
-
let docsTools: boolean | undefined =
queryOptions.no_tools && queryOptions.no_tools?.includes('docs') ? false
: queryOptions.tools?.includes('docs') ? true
: defaultOptions.includeDocsTools;
return {
- client: queryOptions.client ?? defaultOptions.client,
- includeDynamicTools: dynamicTools,
- includeAllTools: allTools,
- includeCodeTools: undefined,
includeDocsTools: docsTools,
- filters,
- capabilities: clientCapabilities,
};
}
-
-function getCapabilitiesExplanation(): string {
- return `
-Client Capabilities Explanation:
-
-Different Language Models (LLMs) and the MCP clients that use them have varying limitations in how they handle tool schemas. Capability flags allow you to inform the MCP server about these limitations.
-
-When a capability flag is set to false, the MCP server will automatically adjust the tool schemas to work around that limitation, ensuring broader compatibility.
-
-Available Capabilities:
-
-# top-level-unions
-Some clients/LLMs do not support JSON schemas with a union type (anyOf) at the root level. If a client lacks this capability, the MCP server splits tools with top-level unions into multiple separate tools, one for each variant in the union.
-
-# refs
-Some clients/LLMs do not support $ref pointers for schema reuse. If a client lacks this capability, the MCP server automatically inlines all references ($defs) directly into the schema. Properties that would cause circular references are removed during this process.
-
-# valid-json
-Some clients/LLMs may incorrectly send arguments as a JSON-encoded string instead of a proper JSON object. If a client *has* this capability, the MCP server will attempt to parse string values as JSON if the initial validation against the schema fails.
-
-# unions
-Some clients/LLMs do not support union types (anyOf) in JSON schemas. If a client lacks this capability, the MCP server removes all anyOf fields and uses only the first variant as the schema.
-
-# formats
-Some clients/LLMs do not support the 'format' keyword in JSON Schema specifications. If a client lacks this capability, the MCP server removes all format fields and appends the format information to the field's description in parentheses.
-
-# tool-name-length=N
-Some clients/LLMs impose a maximum length on tool names. If this capability is set, the MCP server will automatically truncate tool names exceeding the specified length (N), ensuring uniqueness by appending numbers if necessary.
-
-Client Presets (--client):
-Presets like '--client=openai-agents' or '--client=cursor' automatically configure these capabilities based on current known limitations of those clients, simplifying setup.
-
-Current presets:
-${JSON.stringify(knownClients, null, 2)}
- `;
-}
-
-function examples(): [string, string][] {
- const firstEndpoint = endpoints[0]!;
- const secondEndpoint =
- endpoints.find((e) => e.metadata.resource !== firstEndpoint.metadata.resource) || endpoints[1];
- const tag = endpoints.find((e) => e.metadata.tags.length > 0)?.metadata.tags[0];
- const otherEndpoint = secondEndpoint || firstEndpoint;
-
- return [
- [
- `--tool="${firstEndpoint.tool.name}" ${secondEndpoint ? `--tool="${secondEndpoint.tool.name}"` : ''}`,
- 'Include tools by name',
- ],
- [
- `--resource="${firstEndpoint.metadata.resource}" --operation="read"`,
- 'Filter by resource and operation',
- ],
- [
- `--resource="${otherEndpoint.metadata.resource}*" --no-tool="${otherEndpoint.tool.name}"`,
- 'Use resource wildcards and exclusions',
- ],
- [`--client="cursor"`, 'Adjust schemas to be more compatible with Cursor'],
- [
- `--capability="top-level-unions" --capability="tool-name-length=40"`,
- 'Specify individual client capabilities',
- ],
- [
- `--client="cursor" --no-capability="tool-name-length"`,
- 'Use cursor client preset but remove tool name length limit',
- ],
- ...(tag ? [[`--tag="${tag}"`, 'Filter based on tags'] as [string, string]] : []),
- ];
-}
diff --git a/packages/mcp-server/src/server.ts b/packages/mcp-server/src/server.ts
index 457cbb4b..1a471df0 100644
--- a/packages/mcp-server/src/server.ts
+++ b/packages/mcp-server/src/server.ts
@@ -2,39 +2,26 @@
import { Server } from '@modelcontextprotocol/sdk/server/index.js';
import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
-import { Endpoint, endpoints, HandlerFunction, query } from './tools';
import {
CallToolRequestSchema,
ListToolsRequestSchema,
SetLevelRequestSchema,
- Implementation,
- Tool,
} from '@modelcontextprotocol/sdk/types.js';
import { ClientOptions } from '@imagekit/nodejs';
import ImageKit from '@imagekit/nodejs';
-import {
- applyCompatibilityTransformations,
- ClientCapabilities,
- defaultClientCapabilities,
- knownClients,
- parseEmbeddedJSON,
-} from './compat';
-import { dynamicTools } from './dynamic-tools';
import { codeTool } from './code-tool';
import docsSearchTool from './docs-search-tool';
import { McpOptions } from './options';
+import { HandlerFunction, McpTool } from './types';
export { McpOptions } from './options';
-export { ClientType } from './compat';
-export { Filter } from './tools';
export { ClientOptions } from '@imagekit/nodejs';
-export { endpoints } from './tools';
export const newMcpServer = () =>
new McpServer(
{
name: 'imagekit_nodejs_api',
- version: '7.1.1',
+ version: '8.0.0',
},
{ capabilities: { tools: {}, logging: {} } },
);
@@ -52,25 +39,6 @@ export function initMcpServer(params: {
mcpOptions?: McpOptions;
}) {
const server = params.server instanceof McpServer ? params.server.server : params.server;
- const mcpOptions = params.mcpOptions ?? {};
-
- let providedEndpoints: Endpoint[] | null = null;
- let endpointMap: Record | null = null;
-
- const initTools = async (implementation?: Implementation) => {
- if (implementation && (!mcpOptions.client || mcpOptions.client === 'infer')) {
- mcpOptions.client =
- implementation.name.toLowerCase().includes('claude') ? 'claude'
- : implementation.name.toLowerCase().includes('cursor') ? 'cursor'
- : undefined;
- mcpOptions.capabilities = {
- ...(mcpOptions.client && knownClients[mcpOptions.client]),
- ...mcpOptions.capabilities,
- };
- }
- providedEndpoints ??= await selectTools(endpoints, mcpOptions);
- endpointMap ??= Object.fromEntries(providedEndpoints.map((endpoint) => [endpoint.tool.name, endpoint]));
- };
const logAtLevel =
(level: 'debug' | 'info' | 'warning' | 'error') =>
@@ -96,26 +64,23 @@ export function initMcpServer(params: {
},
});
+ const providedTools = selectTools(params.mcpOptions);
+ const toolMap = Object.fromEntries(providedTools.map((mcpTool) => [mcpTool.tool.name, mcpTool]));
+
server.setRequestHandler(ListToolsRequestSchema, async () => {
- if (providedEndpoints === null) {
- await initTools(server.getClientVersion());
- }
return {
- tools: providedEndpoints!.map((endpoint) => endpoint.tool),
+ tools: providedTools.map((mcpTool) => mcpTool.tool),
};
});
server.setRequestHandler(CallToolRequestSchema, async (request) => {
- if (endpointMap === null) {
- await initTools(server.getClientVersion());
- }
const { name, arguments: args } = request.params;
- const endpoint = endpointMap![name];
- if (!endpoint) {
+ const mcpTool = toolMap[name];
+ if (!mcpTool) {
throw new Error(`Unknown tool: ${name}`);
}
- return executeHandler(endpoint.tool, endpoint.handler, client, args, mcpOptions.capabilities);
+ return executeHandler(mcpTool.handler, client, args);
});
server.setRequestHandler(SetLevelRequestSchema, async (request) => {
@@ -145,47 +110,22 @@ export function initMcpServer(params: {
/**
* Selects the tools to include in the MCP Server based on the provided options.
*/
-export async function selectTools(endpoints: Endpoint[], options?: McpOptions): Promise {
- const filteredEndpoints = query(options?.filters ?? [], endpoints);
-
- let includedTools = filteredEndpoints.slice();
-
- if (includedTools.length > 0) {
- if (options?.includeDynamicTools) {
- includedTools = dynamicTools(includedTools);
- }
- } else {
- if (options?.includeAllTools) {
- includedTools = endpoints.slice();
- } else if (options?.includeDynamicTools) {
- includedTools = dynamicTools(endpoints);
- } else if (options?.includeCodeTools) {
- includedTools = [await codeTool()];
- } else {
- includedTools = endpoints.slice();
- }
- }
+export function selectTools(options?: McpOptions): McpTool[] {
+ const includedTools = [codeTool()];
if (options?.includeDocsTools ?? true) {
includedTools.push(docsSearchTool);
}
- const capabilities = { ...defaultClientCapabilities, ...options?.capabilities };
- return applyCompatibilityTransformations(includedTools, capabilities);
+ return includedTools;
}
/**
* Runs the provided handler with the given client and arguments.
*/
export async function executeHandler(
- tool: Tool,
handler: HandlerFunction,
client: ImageKit,
args: Record | undefined,
- compatibilityOptions?: Partial,
) {
- const options = { ...defaultClientCapabilities, ...compatibilityOptions };
- if (!options.validJson && args) {
- args = parseEmbeddedJSON(args, tool.inputSchema);
- }
return await handler(client, args || {});
}
diff --git a/packages/mcp-server/src/stdio.ts b/packages/mcp-server/src/stdio.ts
index d902a5bb..f07696f3 100644
--- a/packages/mcp-server/src/stdio.ts
+++ b/packages/mcp-server/src/stdio.ts
@@ -1,11 +1,10 @@
import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
import { initMcpServer, newMcpServer } from './server';
-import { McpOptions } from './options';
-export const launchStdioServer = async (options: McpOptions) => {
+export const launchStdioServer = async () => {
const server = newMcpServer();
- initMcpServer({ server, mcpOptions: options });
+ initMcpServer({ server });
const transport = new StdioServerTransport();
await server.connect(transport);
diff --git a/packages/mcp-server/src/tools.ts b/packages/mcp-server/src/tools.ts
deleted file mode 100644
index 7e516de7..00000000
--- a/packages/mcp-server/src/tools.ts
+++ /dev/null
@@ -1 +0,0 @@
-export * from './tools/index';
diff --git a/packages/mcp-server/src/tools/accounts/origins/create-accounts-origins.ts b/packages/mcp-server/src/tools/accounts/origins/create-accounts-origins.ts
deleted file mode 100644
index e46f5680..00000000
--- a/packages/mcp-server/src/tools/accounts/origins/create-accounts-origins.ts
+++ /dev/null
@@ -1,318 +0,0 @@
-// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
-
-import { Metadata, asTextContentResult } from '@imagekit/api-mcp/tools/types';
-
-import { Tool } from '@modelcontextprotocol/sdk/types.js';
-import ImageKit from '@imagekit/nodejs';
-
-export const metadata: Metadata = {
- resource: 'accounts.origins',
- operation: 'write',
- tags: [],
- httpMethod: 'post',
- httpPath: '/v1/accounts/origins',
- operationId: 'create-origin',
-};
-
-export const tool: Tool = {
- name: 'create_accounts_origins',
- description:
- '**Note:** This API is currently in beta. \nCreates a new origin and returns the origin object.\n',
- inputSchema: {
- type: 'object',
- anyOf: [
- {
- type: 'object',
- properties: {
- accessKey: {
- type: 'string',
- description: 'Access key for the bucket.',
- },
- bucket: {
- type: 'string',
- description: 'S3 bucket name.',
- },
- name: {
- type: 'string',
- description: 'Display name of the origin.',
- },
- secretKey: {
- type: 'string',
- description: 'Secret key for the bucket.',
- },
- type: {
- type: 'string',
- enum: ['S3'],
- },
- baseUrlForCanonicalHeader: {
- type: 'string',
- description: 'URL used in the Canonical header (if enabled).',
- },
- includeCanonicalHeader: {
- type: 'boolean',
- description: 'Whether to send a Canonical header.',
- },
- prefix: {
- type: 'string',
- description: 'Path prefix inside the bucket.',
- },
- },
- required: ['accessKey', 'bucket', 'name', 'secretKey', 'type'],
- },
- {
- type: 'object',
- properties: {
- accessKey: {
- type: 'string',
- description: 'Access key for the bucket.',
- },
- bucket: {
- type: 'string',
- description: 'S3 bucket name.',
- },
- endpoint: {
- type: 'string',
- description: 'Custom S3-compatible endpoint.',
- },
- name: {
- type: 'string',
- description: 'Display name of the origin.',
- },
- secretKey: {
- type: 'string',
- description: 'Secret key for the bucket.',
- },
- type: {
- type: 'string',
- enum: ['S3_COMPATIBLE'],
- },
- baseUrlForCanonicalHeader: {
- type: 'string',
- description: 'URL used in the Canonical header (if enabled).',
- },
- includeCanonicalHeader: {
- type: 'boolean',
- description: 'Whether to send a Canonical header.',
- },
- prefix: {
- type: 'string',
- description: 'Path prefix inside the bucket.',
- },
- s3ForcePathStyle: {
- type: 'boolean',
- description: 'Use path-style S3 URLs?',
- },
- },
- required: ['accessKey', 'bucket', 'endpoint', 'name', 'secretKey', 'type'],
- },
- {
- type: 'object',
- properties: {
- accessKey: {
- type: 'string',
- description: 'Access key for the bucket.',
- },
- bucket: {
- type: 'string',
- description: 'S3 bucket name.',
- },
- name: {
- type: 'string',
- description: 'Display name of the origin.',
- },
- secretKey: {
- type: 'string',
- description: 'Secret key for the bucket.',
- },
- type: {
- type: 'string',
- enum: ['CLOUDINARY_BACKUP'],
- },
- baseUrlForCanonicalHeader: {
- type: 'string',
- description: 'URL used in the Canonical header (if enabled).',
- },
- includeCanonicalHeader: {
- type: 'boolean',
- description: 'Whether to send a Canonical header.',
- },
- prefix: {
- type: 'string',
- description: 'Path prefix inside the bucket.',
- },
- },
- required: ['accessKey', 'bucket', 'name', 'secretKey', 'type'],
- },
- {
- type: 'object',
- properties: {
- baseUrl: {
- type: 'string',
- description: 'Root URL for the web folder origin.',
- },
- name: {
- type: 'string',
- description: 'Display name of the origin.',
- },
- type: {
- type: 'string',
- enum: ['WEB_FOLDER'],
- },
- baseUrlForCanonicalHeader: {
- type: 'string',
- description: 'URL used in the Canonical header (if enabled).',
- },
- forwardHostHeaderToOrigin: {
- type: 'boolean',
- description: 'Forward the Host header to origin?',
- },
- includeCanonicalHeader: {
- type: 'boolean',
- description: 'Whether to send a Canonical header.',
- },
- },
- required: ['baseUrl', 'name', 'type'],
- },
- {
- type: 'object',
- properties: {
- name: {
- type: 'string',
- description: 'Display name of the origin.',
- },
- type: {
- type: 'string',
- enum: ['WEB_PROXY'],
- },
- baseUrlForCanonicalHeader: {
- type: 'string',
- description: 'URL used in the Canonical header (if enabled).',
- },
- includeCanonicalHeader: {
- type: 'boolean',
- description: 'Whether to send a Canonical header.',
- },
- },
- required: ['name', 'type'],
- },
- {
- type: 'object',
- properties: {
- bucket: {
- type: 'string',
- },
- clientEmail: {
- type: 'string',
- },
- name: {
- type: 'string',
- description: 'Display name of the origin.',
- },
- privateKey: {
- type: 'string',
- },
- type: {
- type: 'string',
- enum: ['GCS'],
- },
- baseUrlForCanonicalHeader: {
- type: 'string',
- description: 'URL used in the Canonical header (if enabled).',
- },
- includeCanonicalHeader: {
- type: 'boolean',
- description: 'Whether to send a Canonical header.',
- },
- prefix: {
- type: 'string',
- },
- },
- required: ['bucket', 'clientEmail', 'name', 'privateKey', 'type'],
- },
- {
- type: 'object',
- properties: {
- accountName: {
- type: 'string',
- },
- container: {
- type: 'string',
- },
- name: {
- type: 'string',
- description: 'Display name of the origin.',
- },
- sasToken: {
- type: 'string',
- },
- type: {
- type: 'string',
- enum: ['AZURE_BLOB'],
- },
- baseUrlForCanonicalHeader: {
- type: 'string',
- description: 'URL used in the Canonical header (if enabled).',
- },
- includeCanonicalHeader: {
- type: 'boolean',
- description: 'Whether to send a Canonical header.',
- },
- prefix: {
- type: 'string',
- },
- },
- required: ['accountName', 'container', 'name', 'sasToken', 'type'],
- },
- {
- type: 'object',
- properties: {
- baseUrl: {
- type: 'string',
- description: 'Akeneo instance base URL.',
- },
- clientId: {
- type: 'string',
- description: 'Akeneo API client ID.',
- },
- clientSecret: {
- type: 'string',
- description: 'Akeneo API client secret.',
- },
- name: {
- type: 'string',
- description: 'Display name of the origin.',
- },
- password: {
- type: 'string',
- description: 'Akeneo API password.',
- },
- type: {
- type: 'string',
- enum: ['AKENEO_PIM'],
- },
- username: {
- type: 'string',
- description: 'Akeneo API username.',
- },
- baseUrlForCanonicalHeader: {
- type: 'string',
- description: 'URL used in the Canonical header (if enabled).',
- },
- includeCanonicalHeader: {
- type: 'boolean',
- description: 'Whether to send a Canonical header.',
- },
- },
- required: ['baseUrl', 'clientId', 'clientSecret', 'name', 'password', 'type', 'username'],
- },
- ],
- },
- annotations: {},
-};
-
-export const handler = async (client: ImageKit, args: Record | undefined) => {
- const body = args as any;
- return asTextContentResult(await client.accounts.origins.create(body));
-};
-
-export default { metadata, tool, handler };
diff --git a/packages/mcp-server/src/tools/accounts/origins/delete-accounts-origins.ts b/packages/mcp-server/src/tools/accounts/origins/delete-accounts-origins.ts
deleted file mode 100644
index 9cb4d97e..00000000
--- a/packages/mcp-server/src/tools/accounts/origins/delete-accounts-origins.ts
+++ /dev/null
@@ -1,43 +0,0 @@
-// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
-
-import { Metadata, asTextContentResult } from '@imagekit/api-mcp/tools/types';
-
-import { Tool } from '@modelcontextprotocol/sdk/types.js';
-import ImageKit from '@imagekit/nodejs';
-
-export const metadata: Metadata = {
- resource: 'accounts.origins',
- operation: 'write',
- tags: [],
- httpMethod: 'delete',
- httpPath: '/v1/accounts/origins/{id}',
- operationId: 'delete-origin',
-};
-
-export const tool: Tool = {
- name: 'delete_accounts_origins',
- description:
- '**Note:** This API is currently in beta. \nPermanently removes the origin identified by `id`. If the origin is in use by any URL‑endpoints, the API will return an error.\n',
- inputSchema: {
- type: 'object',
- properties: {
- id: {
- type: 'string',
- description:
- 'Unique identifier for the origin. This is generated by ImageKit when you create a new origin.',
- },
- },
- required: ['id'],
- },
- annotations: {
- idempotentHint: true,
- },
-};
-
-export const handler = async (client: ImageKit, args: Record | undefined) => {
- const { id, ...body } = args as any;
- const response = await client.accounts.origins.delete(id).asResponse();
- return asTextContentResult(await response.text());
-};
-
-export default { metadata, tool, handler };
diff --git a/packages/mcp-server/src/tools/accounts/origins/get-accounts-origins.ts b/packages/mcp-server/src/tools/accounts/origins/get-accounts-origins.ts
deleted file mode 100644
index 86107b52..00000000
--- a/packages/mcp-server/src/tools/accounts/origins/get-accounts-origins.ts
+++ /dev/null
@@ -1,41 +0,0 @@
-// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
-
-import { Metadata, asTextContentResult } from '@imagekit/api-mcp/tools/types';
-
-import { Tool } from '@modelcontextprotocol/sdk/types.js';
-import ImageKit from '@imagekit/nodejs';
-
-export const metadata: Metadata = {
- resource: 'accounts.origins',
- operation: 'read',
- tags: [],
- httpMethod: 'get',
- httpPath: '/v1/accounts/origins/{id}',
- operationId: 'get-origin',
-};
-
-export const tool: Tool = {
- name: 'get_accounts_origins',
- description: '**Note:** This API is currently in beta. \nRetrieves the origin identified by `id`.\n',
- inputSchema: {
- type: 'object',
- properties: {
- id: {
- type: 'string',
- description:
- 'Unique identifier for the origin. This is generated by ImageKit when you create a new origin.',
- },
- },
- required: ['id'],
- },
- annotations: {
- readOnlyHint: true,
- },
-};
-
-export const handler = async (client: ImageKit, args: Record | undefined) => {
- const { id, ...body } = args as any;
- return asTextContentResult(await client.accounts.origins.get(id));
-};
-
-export default { metadata, tool, handler };
diff --git a/packages/mcp-server/src/tools/accounts/origins/list-accounts-origins.ts b/packages/mcp-server/src/tools/accounts/origins/list-accounts-origins.ts
deleted file mode 100644
index 0510104b..00000000
--- a/packages/mcp-server/src/tools/accounts/origins/list-accounts-origins.ts
+++ /dev/null
@@ -1,35 +0,0 @@
-// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
-
-import { Metadata, asTextContentResult } from '@imagekit/api-mcp/tools/types';
-
-import { Tool } from '@modelcontextprotocol/sdk/types.js';
-import ImageKit from '@imagekit/nodejs';
-
-export const metadata: Metadata = {
- resource: 'accounts.origins',
- operation: 'read',
- tags: [],
- httpMethod: 'get',
- httpPath: '/v1/accounts/origins',
- operationId: 'list-origins',
-};
-
-export const tool: Tool = {
- name: 'list_accounts_origins',
- description:
- '**Note:** This API is currently in beta. \nReturns an array of all configured origins for the current account.\n',
- inputSchema: {
- type: 'object',
- properties: {},
- required: [],
- },
- annotations: {
- readOnlyHint: true,
- },
-};
-
-export const handler = async (client: ImageKit, args: Record | undefined) => {
- return asTextContentResult(await client.accounts.origins.list());
-};
-
-export default { metadata, tool, handler };
diff --git a/packages/mcp-server/src/tools/accounts/origins/update-accounts-origins.ts b/packages/mcp-server/src/tools/accounts/origins/update-accounts-origins.ts
deleted file mode 100644
index 91019fb7..00000000
--- a/packages/mcp-server/src/tools/accounts/origins/update-accounts-origins.ts
+++ /dev/null
@@ -1,360 +0,0 @@
-// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
-
-import { Metadata, asTextContentResult } from '@imagekit/api-mcp/tools/types';
-
-import { Tool } from '@modelcontextprotocol/sdk/types.js';
-import ImageKit from '@imagekit/nodejs';
-
-export const metadata: Metadata = {
- resource: 'accounts.origins',
- operation: 'write',
- tags: [],
- httpMethod: 'put',
- httpPath: '/v1/accounts/origins/{id}',
- operationId: 'update-origin',
-};
-
-export const tool: Tool = {
- name: 'update_accounts_origins',
- description:
- '**Note:** This API is currently in beta. \nUpdates the origin identified by `id` and returns the updated origin object.\n',
- inputSchema: {
- type: 'object',
- anyOf: [
- {
- type: 'object',
- properties: {
- id: {
- type: 'string',
- description:
- 'Unique identifier for the origin. This is generated by ImageKit when you create a new origin.',
- },
- accessKey: {
- type: 'string',
- description: 'Access key for the bucket.',
- },
- bucket: {
- type: 'string',
- description: 'S3 bucket name.',
- },
- name: {
- type: 'string',
- description: 'Display name of the origin.',
- },
- secretKey: {
- type: 'string',
- description: 'Secret key for the bucket.',
- },
- type: {
- type: 'string',
- enum: ['S3'],
- },
- baseUrlForCanonicalHeader: {
- type: 'string',
- description: 'URL used in the Canonical header (if enabled).',
- },
- includeCanonicalHeader: {
- type: 'boolean',
- description: 'Whether to send a Canonical header.',
- },
- prefix: {
- type: 'string',
- description: 'Path prefix inside the bucket.',
- },
- },
- required: ['id', 'accessKey', 'bucket', 'name', 'secretKey', 'type'],
- },
- {
- type: 'object',
- properties: {
- id: {
- type: 'string',
- description:
- 'Unique identifier for the origin. This is generated by ImageKit when you create a new origin.',
- },
- accessKey: {
- type: 'string',
- description: 'Access key for the bucket.',
- },
- bucket: {
- type: 'string',
- description: 'S3 bucket name.',
- },
- endpoint: {
- type: 'string',
- description: 'Custom S3-compatible endpoint.',
- },
- name: {
- type: 'string',
- description: 'Display name of the origin.',
- },
- secretKey: {
- type: 'string',
- description: 'Secret key for the bucket.',
- },
- type: {
- type: 'string',
- enum: ['S3_COMPATIBLE'],
- },
- baseUrlForCanonicalHeader: {
- type: 'string',
- description: 'URL used in the Canonical header (if enabled).',
- },
- includeCanonicalHeader: {
- type: 'boolean',
- description: 'Whether to send a Canonical header.',
- },
- prefix: {
- type: 'string',
- description: 'Path prefix inside the bucket.',
- },
- s3ForcePathStyle: {
- type: 'boolean',
- description: 'Use path-style S3 URLs?',
- },
- },
- required: ['id', 'accessKey', 'bucket', 'endpoint', 'name', 'secretKey', 'type'],
- },
- {
- type: 'object',
- properties: {
- id: {
- type: 'string',
- description:
- 'Unique identifier for the origin. This is generated by ImageKit when you create a new origin.',
- },
- accessKey: {
- type: 'string',
- description: 'Access key for the bucket.',
- },
- bucket: {
- type: 'string',
- description: 'S3 bucket name.',
- },
- name: {
- type: 'string',
- description: 'Display name of the origin.',
- },
- secretKey: {
- type: 'string',
- description: 'Secret key for the bucket.',
- },
- type: {
- type: 'string',
- enum: ['CLOUDINARY_BACKUP'],
- },
- baseUrlForCanonicalHeader: {
- type: 'string',
- description: 'URL used in the Canonical header (if enabled).',
- },
- includeCanonicalHeader: {
- type: 'boolean',
- description: 'Whether to send a Canonical header.',
- },
- prefix: {
- type: 'string',
- description: 'Path prefix inside the bucket.',
- },
- },
- required: ['id', 'accessKey', 'bucket', 'name', 'secretKey', 'type'],
- },
- {
- type: 'object',
- properties: {
- id: {
- type: 'string',
- description:
- 'Unique identifier for the origin. This is generated by ImageKit when you create a new origin.',
- },
- baseUrl: {
- type: 'string',
- description: 'Root URL for the web folder origin.',
- },
- name: {
- type: 'string',
- description: 'Display name of the origin.',
- },
- type: {
- type: 'string',
- enum: ['WEB_FOLDER'],
- },
- baseUrlForCanonicalHeader: {
- type: 'string',
- description: 'URL used in the Canonical header (if enabled).',
- },
- forwardHostHeaderToOrigin: {
- type: 'boolean',
- description: 'Forward the Host header to origin?',
- },
- includeCanonicalHeader: {
- type: 'boolean',
- description: 'Whether to send a Canonical header.',
- },
- },
- required: ['id', 'baseUrl', 'name', 'type'],
- },
- {
- type: 'object',
- properties: {
- id: {
- type: 'string',
- description:
- 'Unique identifier for the origin. This is generated by ImageKit when you create a new origin.',
- },
- name: {
- type: 'string',
- description: 'Display name of the origin.',
- },
- type: {
- type: 'string',
- enum: ['WEB_PROXY'],
- },
- baseUrlForCanonicalHeader: {
- type: 'string',
- description: 'URL used in the Canonical header (if enabled).',
- },
- includeCanonicalHeader: {
- type: 'boolean',
- description: 'Whether to send a Canonical header.',
- },
- },
- required: ['id', 'name', 'type'],
- },
- {
- type: 'object',
- properties: {
- id: {
- type: 'string',
- description:
- 'Unique identifier for the origin. This is generated by ImageKit when you create a new origin.',
- },
- bucket: {
- type: 'string',
- },
- clientEmail: {
- type: 'string',
- },
- name: {
- type: 'string',
- description: 'Display name of the origin.',
- },
- privateKey: {
- type: 'string',
- },
- type: {
- type: 'string',
- enum: ['GCS'],
- },
- baseUrlForCanonicalHeader: {
- type: 'string',
- description: 'URL used in the Canonical header (if enabled).',
- },
- includeCanonicalHeader: {
- type: 'boolean',
- description: 'Whether to send a Canonical header.',
- },
- prefix: {
- type: 'string',
- },
- },
- required: ['id', 'bucket', 'clientEmail', 'name', 'privateKey', 'type'],
- },
- {
- type: 'object',
- properties: {
- id: {
- type: 'string',
- description:
- 'Unique identifier for the origin. This is generated by ImageKit when you create a new origin.',
- },
- accountName: {
- type: 'string',
- },
- container: {
- type: 'string',
- },
- name: {
- type: 'string',
- description: 'Display name of the origin.',
- },
- sasToken: {
- type: 'string',
- },
- type: {
- type: 'string',
- enum: ['AZURE_BLOB'],
- },
- baseUrlForCanonicalHeader: {
- type: 'string',
- description: 'URL used in the Canonical header (if enabled).',
- },
- includeCanonicalHeader: {
- type: 'boolean',
- description: 'Whether to send a Canonical header.',
- },
- prefix: {
- type: 'string',
- },
- },
- required: ['id', 'accountName', 'container', 'name', 'sasToken', 'type'],
- },
- {
- type: 'object',
- properties: {
- id: {
- type: 'string',
- description:
- 'Unique identifier for the origin. This is generated by ImageKit when you create a new origin.',
- },
- baseUrl: {
- type: 'string',
- description: 'Akeneo instance base URL.',
- },
- clientId: {
- type: 'string',
- description: 'Akeneo API client ID.',
- },
- clientSecret: {
- type: 'string',
- description: 'Akeneo API client secret.',
- },
- name: {
- type: 'string',
- description: 'Display name of the origin.',
- },
- password: {
- type: 'string',
- description: 'Akeneo API password.',
- },
- type: {
- type: 'string',
- enum: ['AKENEO_PIM'],
- },
- username: {
- type: 'string',
- description: 'Akeneo API username.',
- },
- baseUrlForCanonicalHeader: {
- type: 'string',
- description: 'URL used in the Canonical header (if enabled).',
- },
- includeCanonicalHeader: {
- type: 'boolean',
- description: 'Whether to send a Canonical header.',
- },
- },
- required: ['id', 'baseUrl', 'clientId', 'clientSecret', 'name', 'password', 'type', 'username'],
- },
- ],
- },
- annotations: {
- idempotentHint: true,
- },
-};
-
-export const handler = async (client: ImageKit, args: Record | undefined) => {
- const { id, ...body } = args as any;
- return asTextContentResult(await client.accounts.origins.update(id, body));
-};
-
-export default { metadata, tool, handler };
diff --git a/packages/mcp-server/src/tools/accounts/url-endpoints/create-accounts-url-endpoints.ts b/packages/mcp-server/src/tools/accounts/url-endpoints/create-accounts-url-endpoints.ts
deleted file mode 100644
index a4152360..00000000
--- a/packages/mcp-server/src/tools/accounts/url-endpoints/create-accounts-url-endpoints.ts
+++ /dev/null
@@ -1,103 +0,0 @@
-// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
-
-import { maybeFilter } from '@imagekit/api-mcp/filtering';
-import { Metadata, asTextContentResult } from '@imagekit/api-mcp/tools/types';
-
-import { Tool } from '@modelcontextprotocol/sdk/types.js';
-import ImageKit from '@imagekit/nodejs';
-
-export const metadata: Metadata = {
- resource: 'accounts.urlEndpoints',
- operation: 'write',
- tags: [],
- httpMethod: 'post',
- httpPath: '/v1/accounts/url-endpoints',
- operationId: 'create-url-endpoint',
-};
-
-export const tool: Tool = {
- name: 'create_accounts_url_endpoints',
- description:
- "When using this tool, always use the `jq_filter` parameter to reduce the response size and improve performance.\n\nOnly omit if you're sure you don't need the data.\n\n**Note:** This API is currently in beta. \nCreates a new URL‑endpoint and returns the resulting object.\n\n\n# Response Schema\n```json\n{\n $ref: '#/$defs/url_endpoint_response',\n $defs: {\n url_endpoint_response: {\n type: 'object',\n title: 'URL‑endpoint Response',\n description: 'URL‑endpoint object as returned by the API.',\n properties: {\n id: {\n type: 'string',\n description: 'Unique identifier for the URL-endpoint. This is generated by ImageKit when you create a new URL-endpoint. For the default URL-endpoint, this is always `default`.'\n },\n description: {\n type: 'string',\n description: 'Description of the URL endpoint.'\n },\n origins: {\n type: 'array',\n description: 'Ordered list of origin IDs to try when the file isn’t in the Media Library; ImageKit checks them in the sequence provided. Origin must be created before it can be used in a URL endpoint.',\n items: {\n type: 'string',\n description: 'Unique identifier for the origin. This is generated by ImageKit when you create a new origin.'\n }\n },\n urlPrefix: {\n type: 'string',\n description: 'Path segment appended to your base URL to form the endpoint (letters, digits, and hyphens only — or empty for the default endpoint).'\n },\n urlRewriter: {\n anyOf: [ {\n type: 'object',\n title: 'Cloudinary URL Rewriter',\n properties: {\n preserveAssetDeliveryTypes: {\n type: 'boolean',\n description: 'Whether to preserve `/` in the rewritten URL.'\n },\n type: {\n type: 'string',\n enum: [ 'CLOUDINARY'\n ]\n }\n },\n required: [ 'preserveAssetDeliveryTypes',\n 'type'\n ]\n },\n {\n type: 'object',\n title: 'Imgix URL Rewriter',\n properties: {\n type: {\n type: 'string',\n enum: [ 'IMGIX'\n ]\n }\n },\n required: [ 'type'\n ]\n },\n {\n type: 'object',\n title: 'Akamai URL Rewriter',\n properties: {\n type: {\n type: 'string',\n enum: [ 'AKAMAI'\n ]\n }\n },\n required: [ 'type'\n ]\n }\n ],\n description: 'Configuration for third-party URL rewriting.'\n }\n },\n required: [ 'id',\n 'description',\n 'origins',\n 'urlPrefix'\n ]\n }\n }\n}\n```",
- inputSchema: {
- type: 'object',
- properties: {
- description: {
- type: 'string',
- description: 'Description of the URL endpoint.',
- },
- origins: {
- type: 'array',
- description:
- 'Ordered list of origin IDs to try when the file isn’t in the Media Library; ImageKit checks them in the sequence provided. Origin must be created before it can be used in a URL endpoint.',
- items: {
- type: 'string',
- description:
- 'Unique identifier for the origin. This is generated by ImageKit when you create a new origin.',
- },
- },
- urlPrefix: {
- type: 'string',
- description:
- 'Path segment appended to your base URL to form the endpoint (letters, digits, and hyphens only — or empty for the default endpoint).',
- },
- urlRewriter: {
- anyOf: [
- {
- type: 'object',
- title: 'Cloudinary URL Rewriter',
- properties: {
- type: {
- type: 'string',
- enum: ['CLOUDINARY'],
- },
- preserveAssetDeliveryTypes: {
- type: 'boolean',
- description: 'Whether to preserve `/` in the rewritten URL.',
- },
- },
- required: ['type'],
- },
- {
- type: 'object',
- title: 'Imgix URL Rewriter',
- properties: {
- type: {
- type: 'string',
- enum: ['IMGIX'],
- },
- },
- required: ['type'],
- },
- {
- type: 'object',
- title: 'Akamai URL Rewriter',
- properties: {
- type: {
- type: 'string',
- enum: ['AKAMAI'],
- },
- },
- required: ['type'],
- },
- ],
- description: 'Configuration for third-party URL rewriting.',
- },
- jq_filter: {
- type: 'string',
- title: 'jq Filter',
- description:
- 'A jq filter to apply to the response to include certain fields. Consult the output schema in the tool description to see the fields that are available.\n\nFor example: to include only the `name` field in every object of a results array, you can provide ".results[].name".\n\nFor more information, see the [jq documentation](https://jqlang.org/manual/).',
- },
- },
- required: ['description'],
- },
- annotations: {},
-};
-
-export const handler = async (client: ImageKit, args: Record | undefined) => {
- const { jq_filter, ...body } = args as any;
- return asTextContentResult(await maybeFilter(jq_filter, await client.accounts.urlEndpoints.create(body)));
-};
-
-export default { metadata, tool, handler };
diff --git a/packages/mcp-server/src/tools/accounts/url-endpoints/delete-accounts-url-endpoints.ts b/packages/mcp-server/src/tools/accounts/url-endpoints/delete-accounts-url-endpoints.ts
deleted file mode 100644
index f6894b47..00000000
--- a/packages/mcp-server/src/tools/accounts/url-endpoints/delete-accounts-url-endpoints.ts
+++ /dev/null
@@ -1,43 +0,0 @@
-// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
-
-import { Metadata, asTextContentResult } from '@imagekit/api-mcp/tools/types';
-
-import { Tool } from '@modelcontextprotocol/sdk/types.js';
-import ImageKit from '@imagekit/nodejs';
-
-export const metadata: Metadata = {
- resource: 'accounts.urlEndpoints',
- operation: 'write',
- tags: [],
- httpMethod: 'delete',
- httpPath: '/v1/accounts/url-endpoints/{id}',
- operationId: 'delete-url-endpoint',
-};
-
-export const tool: Tool = {
- name: 'delete_accounts_url_endpoints',
- description:
- '**Note:** This API is currently in beta. \nDeletes the URL‑endpoint identified by `id`. You cannot delete the default URL‑endpoint created by ImageKit during account creation.\n',
- inputSchema: {
- type: 'object',
- properties: {
- id: {
- type: 'string',
- description:
- 'Unique identifier for the URL-endpoint. This is generated by ImageKit when you create a new URL-endpoint. For the default URL-endpoint, this is always `default`.',
- },
- },
- required: ['id'],
- },
- annotations: {
- idempotentHint: true,
- },
-};
-
-export const handler = async (client: ImageKit, args: Record | undefined) => {
- const { id, ...body } = args as any;
- const response = await client.accounts.urlEndpoints.delete(id).asResponse();
- return asTextContentResult(await response.text());
-};
-
-export default { metadata, tool, handler };
diff --git a/packages/mcp-server/src/tools/accounts/url-endpoints/get-accounts-url-endpoints.ts b/packages/mcp-server/src/tools/accounts/url-endpoints/get-accounts-url-endpoints.ts
deleted file mode 100644
index 440628ad..00000000
--- a/packages/mcp-server/src/tools/accounts/url-endpoints/get-accounts-url-endpoints.ts
+++ /dev/null
@@ -1,49 +0,0 @@
-// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
-
-import { maybeFilter } from '@imagekit/api-mcp/filtering';
-import { Metadata, asTextContentResult } from '@imagekit/api-mcp/tools/types';
-
-import { Tool } from '@modelcontextprotocol/sdk/types.js';
-import ImageKit from '@imagekit/nodejs';
-
-export const metadata: Metadata = {
- resource: 'accounts.urlEndpoints',
- operation: 'read',
- tags: [],
- httpMethod: 'get',
- httpPath: '/v1/accounts/url-endpoints/{id}',
- operationId: 'get-url-endpoint',
-};
-
-export const tool: Tool = {
- name: 'get_accounts_url_endpoints',
- description:
- "When using this tool, always use the `jq_filter` parameter to reduce the response size and improve performance.\n\nOnly omit if you're sure you don't need the data.\n\n**Note:** This API is currently in beta. \nRetrieves the URL‑endpoint identified by `id`.\n\n\n# Response Schema\n```json\n{\n $ref: '#/$defs/url_endpoint_response',\n $defs: {\n url_endpoint_response: {\n type: 'object',\n title: 'URL‑endpoint Response',\n description: 'URL‑endpoint object as returned by the API.',\n properties: {\n id: {\n type: 'string',\n description: 'Unique identifier for the URL-endpoint. This is generated by ImageKit when you create a new URL-endpoint. For the default URL-endpoint, this is always `default`.'\n },\n description: {\n type: 'string',\n description: 'Description of the URL endpoint.'\n },\n origins: {\n type: 'array',\n description: 'Ordered list of origin IDs to try when the file isn’t in the Media Library; ImageKit checks them in the sequence provided. Origin must be created before it can be used in a URL endpoint.',\n items: {\n type: 'string',\n description: 'Unique identifier for the origin. This is generated by ImageKit when you create a new origin.'\n }\n },\n urlPrefix: {\n type: 'string',\n description: 'Path segment appended to your base URL to form the endpoint (letters, digits, and hyphens only — or empty for the default endpoint).'\n },\n urlRewriter: {\n anyOf: [ {\n type: 'object',\n title: 'Cloudinary URL Rewriter',\n properties: {\n preserveAssetDeliveryTypes: {\n type: 'boolean',\n description: 'Whether to preserve `/` in the rewritten URL.'\n },\n type: {\n type: 'string',\n enum: [ 'CLOUDINARY'\n ]\n }\n },\n required: [ 'preserveAssetDeliveryTypes',\n 'type'\n ]\n },\n {\n type: 'object',\n title: 'Imgix URL Rewriter',\n properties: {\n type: {\n type: 'string',\n enum: [ 'IMGIX'\n ]\n }\n },\n required: [ 'type'\n ]\n },\n {\n type: 'object',\n title: 'Akamai URL Rewriter',\n properties: {\n type: {\n type: 'string',\n enum: [ 'AKAMAI'\n ]\n }\n },\n required: [ 'type'\n ]\n }\n ],\n description: 'Configuration for third-party URL rewriting.'\n }\n },\n required: [ 'id',\n 'description',\n 'origins',\n 'urlPrefix'\n ]\n }\n }\n}\n```",
- inputSchema: {
- type: 'object',
- properties: {
- id: {
- type: 'string',
- description:
- 'Unique identifier for the URL-endpoint. This is generated by ImageKit when you create a new URL-endpoint. For the default URL-endpoint, this is always `default`.',
- },
- jq_filter: {
- type: 'string',
- title: 'jq Filter',
- description:
- 'A jq filter to apply to the response to include certain fields. Consult the output schema in the tool description to see the fields that are available.\n\nFor example: to include only the `name` field in every object of a results array, you can provide ".results[].name".\n\nFor more information, see the [jq documentation](https://jqlang.org/manual/).',
- },
- },
- required: ['id'],
- },
- annotations: {
- readOnlyHint: true,
- },
-};
-
-export const handler = async (client: ImageKit, args: Record | undefined) => {
- const { id, jq_filter, ...body } = args as any;
- return asTextContentResult(await maybeFilter(jq_filter, await client.accounts.urlEndpoints.get(id)));
-};
-
-export default { metadata, tool, handler };
diff --git a/packages/mcp-server/src/tools/accounts/url-endpoints/list-accounts-url-endpoints.ts b/packages/mcp-server/src/tools/accounts/url-endpoints/list-accounts-url-endpoints.ts
deleted file mode 100644
index b565f8ad..00000000
--- a/packages/mcp-server/src/tools/accounts/url-endpoints/list-accounts-url-endpoints.ts
+++ /dev/null
@@ -1,44 +0,0 @@
-// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
-
-import { maybeFilter } from '@imagekit/api-mcp/filtering';
-import { Metadata, asTextContentResult } from '@imagekit/api-mcp/tools/types';
-
-import { Tool } from '@modelcontextprotocol/sdk/types.js';
-import ImageKit from '@imagekit/nodejs';
-
-export const metadata: Metadata = {
- resource: 'accounts.urlEndpoints',
- operation: 'read',
- tags: [],
- httpMethod: 'get',
- httpPath: '/v1/accounts/url-endpoints',
- operationId: 'list-url-endpoints',
-};
-
-export const tool: Tool = {
- name: 'list_accounts_url_endpoints',
- description:
- "When using this tool, always use the `jq_filter` parameter to reduce the response size and improve performance.\n\nOnly omit if you're sure you don't need the data.\n\n**Note:** This API is currently in beta. \nReturns an array of all URL‑endpoints configured including the default URL-endpoint generated by ImageKit during account creation.\n\n\n# Response Schema\n```json\n{\n type: 'array',\n items: {\n $ref: '#/$defs/url_endpoint_response'\n },\n $defs: {\n url_endpoint_response: {\n type: 'object',\n title: 'URL‑endpoint Response',\n description: 'URL‑endpoint object as returned by the API.',\n properties: {\n id: {\n type: 'string',\n description: 'Unique identifier for the URL-endpoint. This is generated by ImageKit when you create a new URL-endpoint. For the default URL-endpoint, this is always `default`.'\n },\n description: {\n type: 'string',\n description: 'Description of the URL endpoint.'\n },\n origins: {\n type: 'array',\n description: 'Ordered list of origin IDs to try when the file isn’t in the Media Library; ImageKit checks them in the sequence provided. Origin must be created before it can be used in a URL endpoint.',\n items: {\n type: 'string',\n description: 'Unique identifier for the origin. This is generated by ImageKit when you create a new origin.'\n }\n },\n urlPrefix: {\n type: 'string',\n description: 'Path segment appended to your base URL to form the endpoint (letters, digits, and hyphens only — or empty for the default endpoint).'\n },\n urlRewriter: {\n anyOf: [ {\n type: 'object',\n title: 'Cloudinary URL Rewriter',\n properties: {\n preserveAssetDeliveryTypes: {\n type: 'boolean',\n description: 'Whether to preserve `/` in the rewritten URL.'\n },\n type: {\n type: 'string',\n enum: [ 'CLOUDINARY'\n ]\n }\n },\n required: [ 'preserveAssetDeliveryTypes',\n 'type'\n ]\n },\n {\n type: 'object',\n title: 'Imgix URL Rewriter',\n properties: {\n type: {\n type: 'string',\n enum: [ 'IMGIX'\n ]\n }\n },\n required: [ 'type'\n ]\n },\n {\n type: 'object',\n title: 'Akamai URL Rewriter',\n properties: {\n type: {\n type: 'string',\n enum: [ 'AKAMAI'\n ]\n }\n },\n required: [ 'type'\n ]\n }\n ],\n description: 'Configuration for third-party URL rewriting.'\n }\n },\n required: [ 'id',\n 'description',\n 'origins',\n 'urlPrefix'\n ]\n }\n }\n}\n```",
- inputSchema: {
- type: 'object',
- properties: {
- jq_filter: {
- type: 'string',
- title: 'jq Filter',
- description:
- 'A jq filter to apply to the response to include certain fields. Consult the output schema in the tool description to see the fields that are available.\n\nFor example: to include only the `name` field in every object of a results array, you can provide ".results[].name".\n\nFor more information, see the [jq documentation](https://jqlang.org/manual/).',
- },
- },
- required: [],
- },
- annotations: {
- readOnlyHint: true,
- },
-};
-
-export const handler = async (client: ImageKit, args: Record | undefined) => {
- const { jq_filter } = args as any;
- return asTextContentResult(await maybeFilter(jq_filter, await client.accounts.urlEndpoints.list()));
-};
-
-export default { metadata, tool, handler };
diff --git a/packages/mcp-server/src/tools/accounts/url-endpoints/update-accounts-url-endpoints.ts b/packages/mcp-server/src/tools/accounts/url-endpoints/update-accounts-url-endpoints.ts
deleted file mode 100644
index 6e9969b2..00000000
--- a/packages/mcp-server/src/tools/accounts/url-endpoints/update-accounts-url-endpoints.ts
+++ /dev/null
@@ -1,112 +0,0 @@
-// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
-
-import { maybeFilter } from '@imagekit/api-mcp/filtering';
-import { Metadata, asTextContentResult } from '@imagekit/api-mcp/tools/types';
-
-import { Tool } from '@modelcontextprotocol/sdk/types.js';
-import ImageKit from '@imagekit/nodejs';
-
-export const metadata: Metadata = {
- resource: 'accounts.urlEndpoints',
- operation: 'write',
- tags: [],
- httpMethod: 'put',
- httpPath: '/v1/accounts/url-endpoints/{id}',
- operationId: 'update-url-endpoint',
-};
-
-export const tool: Tool = {
- name: 'update_accounts_url_endpoints',
- description:
- "When using this tool, always use the `jq_filter` parameter to reduce the response size and improve performance.\n\nOnly omit if you're sure you don't need the data.\n\n**Note:** This API is currently in beta. \nUpdates the URL‑endpoint identified by `id` and returns the updated object.\n\n\n# Response Schema\n```json\n{\n $ref: '#/$defs/url_endpoint_response',\n $defs: {\n url_endpoint_response: {\n type: 'object',\n title: 'URL‑endpoint Response',\n description: 'URL‑endpoint object as returned by the API.',\n properties: {\n id: {\n type: 'string',\n description: 'Unique identifier for the URL-endpoint. This is generated by ImageKit when you create a new URL-endpoint. For the default URL-endpoint, this is always `default`.'\n },\n description: {\n type: 'string',\n description: 'Description of the URL endpoint.'\n },\n origins: {\n type: 'array',\n description: 'Ordered list of origin IDs to try when the file isn’t in the Media Library; ImageKit checks them in the sequence provided. Origin must be created before it can be used in a URL endpoint.',\n items: {\n type: 'string',\n description: 'Unique identifier for the origin. This is generated by ImageKit when you create a new origin.'\n }\n },\n urlPrefix: {\n type: 'string',\n description: 'Path segment appended to your base URL to form the endpoint (letters, digits, and hyphens only — or empty for the default endpoint).'\n },\n urlRewriter: {\n anyOf: [ {\n type: 'object',\n title: 'Cloudinary URL Rewriter',\n properties: {\n preserveAssetDeliveryTypes: {\n type: 'boolean',\n description: 'Whether to preserve `/` in the rewritten URL.'\n },\n type: {\n type: 'string',\n enum: [ 'CLOUDINARY'\n ]\n }\n },\n required: [ 'preserveAssetDeliveryTypes',\n 'type'\n ]\n },\n {\n type: 'object',\n title: 'Imgix URL Rewriter',\n properties: {\n type: {\n type: 'string',\n enum: [ 'IMGIX'\n ]\n }\n },\n required: [ 'type'\n ]\n },\n {\n type: 'object',\n title: 'Akamai URL Rewriter',\n properties: {\n type: {\n type: 'string',\n enum: [ 'AKAMAI'\n ]\n }\n },\n required: [ 'type'\n ]\n }\n ],\n description: 'Configuration for third-party URL rewriting.'\n }\n },\n required: [ 'id',\n 'description',\n 'origins',\n 'urlPrefix'\n ]\n }\n }\n}\n```",
- inputSchema: {
- type: 'object',
- properties: {
- id: {
- type: 'string',
- description:
- 'Unique identifier for the URL-endpoint. This is generated by ImageKit when you create a new URL-endpoint. For the default URL-endpoint, this is always `default`.',
- },
- description: {
- type: 'string',
- description: 'Description of the URL endpoint.',
- },
- origins: {
- type: 'array',
- description:
- 'Ordered list of origin IDs to try when the file isn’t in the Media Library; ImageKit checks them in the sequence provided. Origin must be created before it can be used in a URL endpoint.',
- items: {
- type: 'string',
- description:
- 'Unique identifier for the origin. This is generated by ImageKit when you create a new origin.',
- },
- },
- urlPrefix: {
- type: 'string',
- description:
- 'Path segment appended to your base URL to form the endpoint (letters, digits, and hyphens only — or empty for the default endpoint).',
- },
- urlRewriter: {
- anyOf: [
- {
- type: 'object',
- title: 'Cloudinary URL Rewriter',
- properties: {
- type: {
- type: 'string',
- enum: ['CLOUDINARY'],
- },
- preserveAssetDeliveryTypes: {
- type: 'boolean',
- description: 'Whether to preserve `/` in the rewritten URL.',
- },
- },
- required: ['type'],
- },
- {
- type: 'object',
- title: 'Imgix URL Rewriter',
- properties: {
- type: {
- type: 'string',
- enum: ['IMGIX'],
- },
- },
- required: ['type'],
- },
- {
- type: 'object',
- title: 'Akamai URL Rewriter',
- properties: {
- type: {
- type: 'string',
- enum: ['AKAMAI'],
- },
- },
- required: ['type'],
- },
- ],
- description: 'Configuration for third-party URL rewriting.',
- },
- jq_filter: {
- type: 'string',
- title: 'jq Filter',
- description:
- 'A jq filter to apply to the response to include certain fields. Consult the output schema in the tool description to see the fields that are available.\n\nFor example: to include only the `name` field in every object of a results array, you can provide ".results[].name".\n\nFor more information, see the [jq documentation](https://jqlang.org/manual/).',
- },
- },
- required: ['id', 'description'],
- },
- annotations: {
- idempotentHint: true,
- },
-};
-
-export const handler = async (client: ImageKit, args: Record | undefined) => {
- const { id, jq_filter, ...body } = args as any;
- return asTextContentResult(
- await maybeFilter(jq_filter, await client.accounts.urlEndpoints.update(id, body)),
- );
-};
-
-export default { metadata, tool, handler };
diff --git a/packages/mcp-server/src/tools/accounts/usage/get-accounts-usage.ts b/packages/mcp-server/src/tools/accounts/usage/get-accounts-usage.ts
deleted file mode 100644
index 09f47703..00000000
--- a/packages/mcp-server/src/tools/accounts/usage/get-accounts-usage.ts
+++ /dev/null
@@ -1,56 +0,0 @@
-// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
-
-import { maybeFilter } from '@imagekit/api-mcp/filtering';
-import { Metadata, asTextContentResult } from '@imagekit/api-mcp/tools/types';
-
-import { Tool } from '@modelcontextprotocol/sdk/types.js';
-import ImageKit from '@imagekit/nodejs';
-
-export const metadata: Metadata = {
- resource: 'accounts.usage',
- operation: 'read',
- tags: [],
- httpMethod: 'get',
- httpPath: '/v1/accounts/usage',
- operationId: 'get-usage',
-};
-
-export const tool: Tool = {
- name: 'get_accounts_usage',
- description:
- "When using this tool, always use the `jq_filter` parameter to reduce the response size and improve performance.\n\nOnly omit if you're sure you don't need the data.\n\nGet the account usage information between two dates. Note that the API response includes data from the start date while excluding data from the end date. In other words, the data covers the period starting from the specified start date up to, but not including, the end date.\n\n\n# Response Schema\n```json\n{\n type: 'object',\n properties: {\n bandwidthBytes: {\n type: 'integer',\n description: 'Amount of bandwidth used in bytes.'\n },\n extensionUnitsCount: {\n type: 'integer',\n description: 'Number of extension units used.'\n },\n mediaLibraryStorageBytes: {\n type: 'integer',\n description: 'Storage used by media library in bytes.'\n },\n originalCacheStorageBytes: {\n type: 'integer',\n description: 'Storage used by the original cache in bytes.'\n },\n videoProcessingUnitsCount: {\n type: 'integer',\n description: 'Number of video processing units used.'\n }\n }\n}\n```",
- inputSchema: {
- type: 'object',
- properties: {
- endDate: {
- type: 'string',
- description:
- 'Specify a `endDate` in `YYYY-MM-DD` format. It should be after the `startDate`. The difference between `startDate` and `endDate` should be less than 90 days.',
- format: 'date',
- },
- startDate: {
- type: 'string',
- description:
- 'Specify a `startDate` in `YYYY-MM-DD` format. It should be before the `endDate`. The difference between `startDate` and `endDate` should be less than 90 days.',
- format: 'date',
- },
- jq_filter: {
- type: 'string',
- title: 'jq Filter',
- description:
- 'A jq filter to apply to the response to include certain fields. Consult the output schema in the tool description to see the fields that are available.\n\nFor example: to include only the `name` field in every object of a results array, you can provide ".results[].name".\n\nFor more information, see the [jq documentation](https://jqlang.org/manual/).',
- },
- },
- required: ['endDate', 'startDate'],
- },
- annotations: {
- readOnlyHint: true,
- },
-};
-
-export const handler = async (client: ImageKit, args: Record | undefined) => {
- const { jq_filter, ...body } = args as any;
- return asTextContentResult(await maybeFilter(jq_filter, await client.accounts.usage.get(body)));
-};
-
-export default { metadata, tool, handler };
diff --git a/packages/mcp-server/src/tools/assets/list-assets.ts b/packages/mcp-server/src/tools/assets/list-assets.ts
deleted file mode 100644
index 6da6273a..00000000
--- a/packages/mcp-server/src/tools/assets/list-assets.ts
+++ /dev/null
@@ -1,94 +0,0 @@
-// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
-
-import { maybeFilter } from '@imagekit/api-mcp/filtering';
-import { Metadata, asTextContentResult } from '@imagekit/api-mcp/tools/types';
-
-import { Tool } from '@modelcontextprotocol/sdk/types.js';
-import ImageKit from '@imagekit/nodejs';
-
-export const metadata: Metadata = {
- resource: 'assets',
- operation: 'read',
- tags: [],
- httpMethod: 'get',
- httpPath: '/v1/files',
- operationId: 'list-and-search-assets',
-};
-
-export const tool: Tool = {
- name: 'list_assets',
- description:
- "When using this tool, always use the `jq_filter` parameter to reduce the response size and improve performance.\n\nOnly omit if you're sure you don't need the data.\n\nThis API can list all the uploaded files and folders in your ImageKit.io media library. In addition, you can fine-tune your query by specifying various filters by generating a query string in a Lucene-like syntax and provide this generated string as the value of the `searchQuery`.\n\n\n# Response Schema\n```json\n{\n type: 'array',\n items: {\n anyOf: [ {\n $ref: '#/$defs/file'\n },\n {\n $ref: '#/$defs/folder'\n }\n ],\n description: 'Object containing details of a file or file version.'\n },\n $defs: {\n file: {\n type: 'object',\n title: 'File & File Version',\n description: 'Object containing details of a file or file version.',\n properties: {\n AITags: {\n type: 'array',\n description: 'An array of tags assigned to the file by auto tagging.\\n',\n items: {\n type: 'object',\n properties: {\n confidence: {\n type: 'number',\n description: 'Confidence score of the tag.'\n },\n name: {\n type: 'string',\n description: 'Name of the tag.'\n },\n source: {\n type: 'string',\n description: 'Source of the tag. Possible values are `google-auto-tagging` and `aws-auto-tagging`.'\n }\n }\n }\n },\n createdAt: {\n type: 'string',\n description: 'Date and time when the file was uploaded. The date and time is in ISO8601 format.\\n',\n format: 'date-time'\n },\n customCoordinates: {\n type: 'string',\n description: 'An string with custom coordinates of the file.\\n'\n },\n customMetadata: {\n type: 'object',\n description: 'An object with custom metadata for the file.\\n',\n additionalProperties: true\n },\n description: {\n type: 'string',\n description: 'Optional text to describe the contents of the file. Can be set by the user or the ai-auto-description extension.\\n'\n },\n fileId: {\n type: 'string',\n description: 'Unique identifier of the asset.'\n },\n filePath: {\n type: 'string',\n description: 'Path of the file. This is the path you would use in the URL to access the file. For example, if the file is at the root of the media library, the path will be `/file.jpg`. If the file is inside a folder named `images`, the path will be `/images/file.jpg`.\\n'\n },\n fileType: {\n type: 'string',\n description: 'Type of the file. Possible values are `image`, `non-image`.\\n'\n },\n hasAlpha: {\n type: 'boolean',\n description: 'Specifies if the image has an alpha channel.\\n'\n },\n height: {\n type: 'number',\n description: 'Height of the file.\\n'\n },\n isPrivateFile: {\n type: 'boolean',\n description: 'Specifies if the file is private or not.\\n'\n },\n isPublished: {\n type: 'boolean',\n description: 'Specifies if the file is published or not.\\n'\n },\n mime: {\n type: 'string',\n description: 'MIME type of the file.\\n'\n },\n name: {\n type: 'string',\n description: 'Name of the asset.'\n },\n selectedFieldsSchema: {\n type: 'object',\n description: 'This field is included in the response only if the Path policy feature is available in the plan.\\nIt contains schema definitions for the custom metadata fields selected for the specified file path.\\nField selection can only be done when the Path policy feature is enabled.\\n\\nKeys are the names of the custom metadata fields; the value object has details about the custom metadata schema.\\n',\n additionalProperties: true\n },\n size: {\n type: 'number',\n description: 'Size of the file in bytes.\\n'\n },\n tags: {\n type: 'array',\n description: 'An array of tags assigned to the file. Tags are used to search files in the media library.\\n',\n items: {\n type: 'string'\n }\n },\n thumbnail: {\n type: 'string',\n description: 'URL of the thumbnail image. This URL is used to access the thumbnail image of the file in the media library.\\n'\n },\n type: {\n type: 'string',\n description: 'Type of the asset.',\n enum: [ 'file',\n 'file-version'\n ]\n },\n updatedAt: {\n type: 'string',\n description: 'Date and time when the file was last updated. The date and time is in ISO8601 format.\\n',\n format: 'date-time'\n },\n url: {\n type: 'string',\n description: 'URL of the file.\\n'\n },\n versionInfo: {\n type: 'object',\n description: 'An object with details of the file version.\\n',\n properties: {\n id: {\n type: 'string',\n description: 'Unique identifier of the file version.'\n },\n name: {\n type: 'string',\n description: 'Name of the file version.'\n }\n }\n },\n width: {\n type: 'number',\n description: 'Width of the file.\\n'\n }\n }\n },\n folder: {\n type: 'object',\n title: 'Folder',\n properties: {\n createdAt: {\n type: 'string',\n description: 'Date and time when the folder was created. The date and time is in ISO8601 format.\\n',\n format: 'date-time'\n },\n folderId: {\n type: 'string',\n description: 'Unique identifier of the asset.'\n },\n folderPath: {\n type: 'string',\n description: 'Path of the folder. This is the path you would use in the URL to access the folder. For example, if the folder is at the root of the media library, the path will be /folder. If the folder is inside another folder named images, the path will be /images/folder.\\n'\n },\n name: {\n type: 'string',\n description: 'Name of the asset.'\n },\n type: {\n type: 'string',\n description: 'Type of the asset.',\n enum: [ 'folder'\n ]\n },\n updatedAt: {\n type: 'string',\n description: 'Date and time when the folder was last updated. The date and time is in ISO8601 format.\\n',\n format: 'date-time'\n }\n }\n }\n }\n}\n```",
- inputSchema: {
- type: 'object',
- properties: {
- fileType: {
- type: 'string',
- description:
- 'Filter results by file type.\n\n- `all` — include all file types \n- `image` — include only image files \n- `non-image` — include only non-image files (e.g., JS, CSS, video)',
- enum: ['all', 'image', 'non-image'],
- },
- limit: {
- type: 'integer',
- description: 'The maximum number of results to return in response.\n',
- },
- path: {
- type: 'string',
- description:
- 'Folder path if you want to limit the search within a specific folder. For example, `/sales-banner/` will only search in folder sales-banner.\n\nNote : If your use case involves searching within a folder as well as its subfolders, you can use `path` parameter in `searchQuery` with appropriate operator.\nCheckout [Supported parameters](/docs/api-reference/digital-asset-management-dam/list-and-search-assets#supported-parameters) for more information.\n',
- },
- searchQuery: {
- type: 'string',
- description:
- 'Query string in a Lucene-like query language e.g. `createdAt > "7d"`.\n\nNote : When the searchQuery parameter is present, the following query parameters will have no effect on the result:\n\n1. `tags`\n2. `type`\n3. `name`\n\n[Learn more](/docs/api-reference/digital-asset-management-dam/list-and-search-assets#advanced-search-queries) from examples.\n',
- },
- skip: {
- type: 'integer',
- description: 'The number of results to skip before returning results.\n',
- },
- sort: {
- type: 'string',
- description: 'Sort the results by one of the supported fields in ascending or descending order.',
- enum: [
- 'ASC_NAME',
- 'DESC_NAME',
- 'ASC_CREATED',
- 'DESC_CREATED',
- 'ASC_UPDATED',
- 'DESC_UPDATED',
- 'ASC_HEIGHT',
- 'DESC_HEIGHT',
- 'ASC_WIDTH',
- 'DESC_WIDTH',
- 'ASC_SIZE',
- 'DESC_SIZE',
- 'ASC_RELEVANCE',
- 'DESC_RELEVANCE',
- ],
- },
- type: {
- type: 'string',
- description:
- 'Filter results by asset type.\n\n- `file` — returns only files \n- `file-version` — returns specific file versions \n- `folder` — returns only folders \n- `all` — returns both files and folders (excludes `file-version`)',
- enum: ['file', 'file-version', 'folder', 'all'],
- },
- jq_filter: {
- type: 'string',
- title: 'jq Filter',
- description:
- 'A jq filter to apply to the response to include certain fields. Consult the output schema in the tool description to see the fields that are available.\n\nFor example: to include only the `name` field in every object of a results array, you can provide ".results[].name".\n\nFor more information, see the [jq documentation](https://jqlang.org/manual/).',
- },
- },
- required: [],
- },
- annotations: {
- readOnlyHint: true,
- },
-};
-
-export const handler = async (client: ImageKit, args: Record | undefined) => {
- const { jq_filter, ...body } = args as any;
- return asTextContentResult(await maybeFilter(jq_filter, await client.assets.list(body)));
-};
-
-export default { metadata, tool, handler };
diff --git a/packages/mcp-server/src/tools/beta/v2/files/upload-v2-beta-files.ts b/packages/mcp-server/src/tools/beta/v2/files/upload-v2-beta-files.ts
deleted file mode 100644
index 9a45009d..00000000
--- a/packages/mcp-server/src/tools/beta/v2/files/upload-v2-beta-files.ts
+++ /dev/null
@@ -1,316 +0,0 @@
-// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
-
-import { Metadata, asTextContentResult } from '@imagekit/api-mcp/tools/types';
-
-import { Tool } from '@modelcontextprotocol/sdk/types.js';
-import ImageKit from '@imagekit/nodejs';
-
-export const metadata: Metadata = {
- resource: 'beta.v2.files',
- operation: 'write',
- tags: [],
- httpMethod: 'post',
- httpPath: '/api/v2/files/upload',
- operationId: 'upload-file-v2',
-};
-
-export const tool: Tool = {
- name: 'upload_v2_beta_files',
- description:
- 'The V2 API enhances security by verifying the entire payload using JWT. This API is in beta.\n\nImageKit.io allows you to upload files directly from both the server and client sides. For server-side uploads, private API key authentication is used. For client-side uploads, generate a one-time `token` from your secure backend using private API. [Learn more](/docs/api-reference/upload-file/upload-file-v2#how-to-implement-secure-client-side-file-upload) about how to implement secure client-side file upload.\n\n**File size limit** \\\nOn the free plan, the maximum upload file sizes are 20MB for images, audio, and raw files, and 100MB for videos. On the paid plan, these limits increase to 40MB for images, audio, and raw files, and 2GB for videos. These limits can be further increased with higher-tier plans.\n\n**Version limit** \\\nA file can have a maximum of 100 versions.\n\n**Demo applications**\n\n- A full-fledged [upload widget using Uppy](https://github.com/imagekit-samples/uppy-uploader), supporting file selections from local storage, URL, Dropbox, Google Drive, Instagram, and more.\n- [Quick start guides](/docs/quick-start-guides) for various frameworks and technologies.\n',
- inputSchema: {
- type: 'object',
- properties: {
- file: {
- type: 'string',
- description:
- 'The API accepts any of the following:\n\n- **Binary data** – send the raw bytes as `multipart/form-data`.\n- **HTTP / HTTPS URL** – a publicly reachable URL that ImageKit’s servers can fetch.\n- **Base64 string** – the file encoded as a Base64 data URI or plain Base64.\n\nWhen supplying a URL, the server must receive the response headers within 8 seconds; otherwise the request fails with 400 Bad Request.\n',
- },
- fileName: {
- type: 'string',
- description: 'The name with which the file has to be uploaded.\n',
- },
- token: {
- type: 'string',
- description:
- "This is the client-generated JSON Web Token (JWT). The ImageKit.io server uses it to authenticate and check that the upload request parameters have not been tampered with after the token has been generated. Learn how to create the token on the page below. This field is only required for authentication when uploading a file from the client side.\n\n\n**Note**: Sending a JWT that has been used in the past will result in a validation error. Even if your previous request resulted in an error, you should always send a new token.\n\n\n**⚠️Warning**: JWT must be generated on the server-side because it is generated using your account's private API key. This field is required for authentication when uploading a file from the client-side.\n",
- },
- checks: {
- type: 'string',
- description:
- 'Server-side checks to run on the asset.\nRead more about [Upload API checks](/docs/api-reference/upload-file/upload-file-v2#upload-api-checks).\n',
- },
- customCoordinates: {
- type: 'string',
- description:
- 'Define an important area in the image. This is only relevant for image type files.\n\n - To be passed as a string with the x and y coordinates of the top-left corner, and width and height of the area of interest in the format `x,y,width,height`. For example - `10,10,100,100`\n - Can be used with fo-customtransformation.\n - If this field is not specified and the file is overwritten, then customCoordinates will be removed.\n',
- },
- customMetadata: {
- type: 'object',
- description:
- 'JSON key-value pairs to associate with the asset. Create the custom metadata fields before setting these values.\n',
- additionalProperties: true,
- },
- description: {
- type: 'string',
- description: 'Optional text to describe the contents of the file.\n',
- },
- extensions: {
- $ref: '#/$defs/extensions',
- },
- folder: {
- type: 'string',
- description:
- "The folder path in which the image has to be uploaded. If the folder(s) didn't exist before, a new folder(s) is created. Using multiple `/` creates a nested folder.\n",
- },
- isPrivateFile: {
- type: 'boolean',
- description:
- 'Whether to mark the file as private or not.\n\nIf `true`, the file is marked as private and is accessible only using named transformation or signed URL.\n',
- },
- isPublished: {
- type: 'boolean',
- description:
- 'Whether to upload file as published or not.\n\nIf `false`, the file is marked as unpublished, which restricts access to the file only via the media library. Files in draft or unpublished state can only be publicly accessed after being published.\n\nThe option to upload in draft state is only available in custom enterprise pricing plans.\n',
- },
- overwriteAITags: {
- type: 'boolean',
- description:
- 'If set to `true` and a file already exists at the exact location, its AITags will be removed. Set `overwriteAITags` to `false` to preserve AITags.\n',
- },
- overwriteCustomMetadata: {
- type: 'boolean',
- description:
- 'If the request does not have `customMetadata`, and a file already exists at the exact location, existing customMetadata will be removed.\n',
- },
- overwriteFile: {
- type: 'boolean',
- description:
- 'If `false` and `useUniqueFileName` is also `false`, and a file already exists at the exact location, upload API will return an error immediately.\n',
- },
- overwriteTags: {
- type: 'boolean',
- description:
- 'If the request does not have `tags`, and a file already exists at the exact location, existing tags will be removed.\n',
- },
- responseFields: {
- type: 'array',
- description: 'Array of response field keys to include in the API response body.\n',
- items: {
- type: 'string',
- enum: [
- 'tags',
- 'customCoordinates',
- 'isPrivateFile',
- 'embeddedMetadata',
- 'isPublished',
- 'customMetadata',
- 'metadata',
- 'selectedFieldsSchema',
- ],
- },
- },
- tags: {
- type: 'array',
- description:
- 'Set the tags while uploading the file.\nProvide an array of tag strings (e.g. `["tag1", "tag2", "tag3"]`). The combined length of all tag characters must not exceed 500, and the `%` character is not allowed.\nIf this field is not specified and the file is overwritten, the existing tags will be removed.\n',
- items: {
- type: 'string',
- },
- },
- transformation: {
- type: 'object',
- description:
- "Configure pre-processing (`pre`) and post-processing (`post`) transformations.\n\n- `pre` — applied before the file is uploaded to the Media Library. \n Useful for reducing file size or applying basic optimizations upfront (e.g., resize, compress).\n\n- `post` — applied immediately after upload. \n Ideal for generating transformed versions (like video encodes or thumbnails) in advance, so they're ready for delivery without delay.\n\nYou can mix and match any combination of post-processing types.\n",
- properties: {
- post: {
- type: 'array',
- description:
- 'List of transformations to apply *after* the file is uploaded. \nEach item must match one of the following types:\n`transformation`, `gif-to-video`, `thumbnail`, `abs`.\n',
- items: {
- anyOf: [
- {
- type: 'object',
- title: 'Simple post-transformation',
- properties: {
- type: {
- type: 'string',
- description: 'Transformation type.',
- enum: ['transformation'],
- },
- value: {
- type: 'string',
- description:
- 'Transformation string (e.g. `w-200,h-200`). \nSame syntax as ImageKit URL-based transformations.\n',
- },
- },
- required: ['type', 'value'],
- },
- {
- type: 'object',
- title: 'Convert GIF to video',
- properties: {
- type: {
- type: 'string',
- description: 'Converts an animated GIF into an MP4.',
- enum: ['gif-to-video'],
- },
- value: {
- type: 'string',
- description:
- 'Optional transformation string to apply to the output video. \n**Example**: `q-80`\n',
- },
- },
- required: ['type'],
- },
- {
- type: 'object',
- title: 'Generate a thumbnail',
- properties: {
- type: {
- type: 'string',
- description: 'Generates a thumbnail image.',
- enum: ['thumbnail'],
- },
- value: {
- type: 'string',
- description: 'Optional transformation string. \n**Example**: `w-150,h-150`\n',
- },
- },
- required: ['type'],
- },
- {
- type: 'object',
- title: 'Adaptive Bitrate Streaming',
- properties: {
- protocol: {
- type: 'string',
- description: 'Streaming protocol to use (`hls` or `dash`).',
- enum: ['hls', 'dash'],
- },
- type: {
- type: 'string',
- description: 'Adaptive Bitrate Streaming (ABS) setup.',
- enum: ['abs'],
- },
- value: {
- type: 'string',
- description:
- 'List of different representations you want to create separated by an underscore.\n',
- },
- },
- required: ['protocol', 'type', 'value'],
- },
- ],
- },
- },
- pre: {
- type: 'string',
- description:
- 'Transformation string to apply before uploading the file to the Media Library. Useful for optimizing files at ingestion.\n',
- },
- },
- },
- useUniqueFileName: {
- type: 'boolean',
- description:
- 'Whether to use a unique filename for this file or not.\n\nIf `true`, ImageKit.io will add a unique suffix to the filename parameter to get a unique filename.\n\nIf `false`, then the image is uploaded with the provided filename parameter, and any existing file with the same name is replaced.\n',
- },
- webhookUrl: {
- type: 'string',
- description:
- 'The final status of extensions after they have completed execution will be delivered to this endpoint as a POST request. [Learn more](/docs/api-reference/digital-asset-management-dam/managing-assets/update-file-details#webhook-payload-structure) about the webhook payload structure.\n',
- },
- },
- required: ['file', 'fileName'],
- $defs: {
- extensions: {
- type: 'array',
- title: 'Extensions Array',
- description:
- 'Array of extensions to be applied to the asset. Each extension can be configured with specific parameters based on the extension type.\n',
- items: {
- anyOf: [
- {
- type: 'object',
- title: 'Remove background',
- properties: {
- name: {
- type: 'string',
- description: 'Specifies the background removal extension.',
- enum: ['remove-bg'],
- },
- options: {
- type: 'object',
- properties: {
- add_shadow: {
- type: 'boolean',
- description:
- 'Whether to add an artificial shadow to the result. Default is false. Note: Adding shadows is currently only supported for car photos.\n',
- },
- bg_color: {
- type: 'string',
- description:
- 'Specifies a solid color background using hex code (e.g., "81d4fa", "fff") or color name (e.g., "green"). If this parameter is set, `bg_image_url` must be empty.\n',
- },
- bg_image_url: {
- type: 'string',
- description:
- 'Sets a background image from a URL. If this parameter is set, `bg_color` must be empty.\n',
- },
- semitransparency: {
- type: 'boolean',
- description:
- 'Allows semi-transparent regions in the result. Default is true. Note: Semitransparency is currently only supported for car windows.\n',
- },
- },
- },
- },
- required: ['name'],
- },
- {
- type: 'object',
- title: 'Auto tagging',
- properties: {
- maxTags: {
- type: 'integer',
- description: 'Maximum number of tags to attach to the asset.',
- },
- minConfidence: {
- type: 'integer',
- description: 'Minimum confidence level for tags to be considered valid.',
- },
- name: {
- type: 'string',
- description: 'Specifies the auto-tagging extension used.',
- enum: ['google-auto-tagging', 'aws-auto-tagging'],
- },
- },
- required: ['maxTags', 'minConfidence', 'name'],
- },
- {
- type: 'object',
- title: 'Auto description',
- properties: {
- name: {
- type: 'string',
- description: 'Specifies the auto description extension.',
- enum: ['ai-auto-description'],
- },
- },
- required: ['name'],
- },
- ],
- },
- },
- },
- },
- annotations: {},
-};
-
-export const handler = async (client: ImageKit, args: Record | undefined) => {
- const body = args as any;
- return asTextContentResult(await client.beta.v2.files.upload(body));
-};
-
-export default { metadata, tool, handler };
diff --git a/packages/mcp-server/src/tools/cache/invalidation/create-cache-invalidation.ts b/packages/mcp-server/src/tools/cache/invalidation/create-cache-invalidation.ts
deleted file mode 100644
index 1e73f174..00000000
--- a/packages/mcp-server/src/tools/cache/invalidation/create-cache-invalidation.ts
+++ /dev/null
@@ -1,46 +0,0 @@
-// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
-
-import { maybeFilter } from '@imagekit/api-mcp/filtering';
-import { Metadata, asTextContentResult } from '@imagekit/api-mcp/tools/types';
-
-import { Tool } from '@modelcontextprotocol/sdk/types.js';
-import ImageKit from '@imagekit/nodejs';
-
-export const metadata: Metadata = {
- resource: 'cache.invalidation',
- operation: 'write',
- tags: [],
- httpMethod: 'post',
- httpPath: '/v1/files/purge',
- operationId: 'purge-cache',
-};
-
-export const tool: Tool = {
- name: 'create_cache_invalidation',
- description:
- "When using this tool, always use the `jq_filter` parameter to reduce the response size and improve performance.\n\nOnly omit if you're sure you don't need the data.\n\nThis API will purge CDN cache and ImageKit.io's internal cache for a file. Note: Purge cache is an asynchronous process and it may take some time to reflect the changes.\n\n\n# Response Schema\n```json\n{\n type: 'object',\n properties: {\n requestId: {\n type: 'string',\n description: 'Unique identifier of the purge request. This can be used to check the status of the purge request.\\n'\n }\n }\n}\n```",
- inputSchema: {
- type: 'object',
- properties: {
- url: {
- type: 'string',
- description: 'The full URL of the file to be purged.\n',
- },
- jq_filter: {
- type: 'string',
- title: 'jq Filter',
- description:
- 'A jq filter to apply to the response to include certain fields. Consult the output schema in the tool description to see the fields that are available.\n\nFor example: to include only the `name` field in every object of a results array, you can provide ".results[].name".\n\nFor more information, see the [jq documentation](https://jqlang.org/manual/).',
- },
- },
- required: ['url'],
- },
- annotations: {},
-};
-
-export const handler = async (client: ImageKit, args: Record | undefined) => {
- const { jq_filter, ...body } = args as any;
- return asTextContentResult(await maybeFilter(jq_filter, await client.cache.invalidation.create(body)));
-};
-
-export default { metadata, tool, handler };
diff --git a/packages/mcp-server/src/tools/cache/invalidation/get-cache-invalidation.ts b/packages/mcp-server/src/tools/cache/invalidation/get-cache-invalidation.ts
deleted file mode 100644
index a9a7afc4..00000000
--- a/packages/mcp-server/src/tools/cache/invalidation/get-cache-invalidation.ts
+++ /dev/null
@@ -1,47 +0,0 @@
-// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
-
-import { maybeFilter } from '@imagekit/api-mcp/filtering';
-import { Metadata, asTextContentResult } from '@imagekit/api-mcp/tools/types';
-
-import { Tool } from '@modelcontextprotocol/sdk/types.js';
-import ImageKit from '@imagekit/nodejs';
-
-export const metadata: Metadata = {
- resource: 'cache.invalidation',
- operation: 'read',
- tags: [],
- httpMethod: 'get',
- httpPath: '/v1/files/purge/{requestId}',
- operationId: 'purge-status',
-};
-
-export const tool: Tool = {
- name: 'get_cache_invalidation',
- description:
- "When using this tool, always use the `jq_filter` parameter to reduce the response size and improve performance.\n\nOnly omit if you're sure you don't need the data.\n\nThis API returns the status of a purge cache request.\n\n\n# Response Schema\n```json\n{\n type: 'object',\n properties: {\n status: {\n type: 'string',\n description: 'Status of the purge request.',\n enum: [ 'Pending',\n 'Completed'\n ]\n }\n }\n}\n```",
- inputSchema: {
- type: 'object',
- properties: {
- requestId: {
- type: 'string',
- },
- jq_filter: {
- type: 'string',
- title: 'jq Filter',
- description:
- 'A jq filter to apply to the response to include certain fields. Consult the output schema in the tool description to see the fields that are available.\n\nFor example: to include only the `name` field in every object of a results array, you can provide ".results[].name".\n\nFor more information, see the [jq documentation](https://jqlang.org/manual/).',
- },
- },
- required: ['requestId'],
- },
- annotations: {
- readOnlyHint: true,
- },
-};
-
-export const handler = async (client: ImageKit, args: Record | undefined) => {
- const { requestId, jq_filter, ...body } = args as any;
- return asTextContentResult(await maybeFilter(jq_filter, await client.cache.invalidation.get(requestId)));
-};
-
-export default { metadata, tool, handler };
diff --git a/packages/mcp-server/src/tools/custom-metadata-fields/create-custom-metadata-fields.ts b/packages/mcp-server/src/tools/custom-metadata-fields/create-custom-metadata-fields.ts
deleted file mode 100644
index 67cf2ec6..00000000
--- a/packages/mcp-server/src/tools/custom-metadata-fields/create-custom-metadata-fields.ts
+++ /dev/null
@@ -1,154 +0,0 @@
-// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
-
-import { maybeFilter } from '@imagekit/api-mcp/filtering';
-import { Metadata, asTextContentResult } from '@imagekit/api-mcp/tools/types';
-
-import { Tool } from '@modelcontextprotocol/sdk/types.js';
-import ImageKit from '@imagekit/nodejs';
-
-export const metadata: Metadata = {
- resource: 'customMetadataFields',
- operation: 'write',
- tags: [],
- httpMethod: 'post',
- httpPath: '/v1/customMetadataFields',
- operationId: 'create-new-field',
-};
-
-export const tool: Tool = {
- name: 'create_custom_metadata_fields',
- description:
- "When using this tool, always use the `jq_filter` parameter to reduce the response size and improve performance.\n\nOnly omit if you're sure you don't need the data.\n\nThis API creates a new custom metadata field. Once a custom metadata field is created either through this API or using the dashboard UI, its value can be set on the assets. The value of a field for an asset can be set using the media library UI or programmatically through upload or update assets API.\n\n\n# Response Schema\n```json\n{\n $ref: '#/$defs/custom_metadata_field',\n $defs: {\n custom_metadata_field: {\n type: 'object',\n description: 'Object containing details of a custom metadata field.',\n properties: {\n id: {\n type: 'string',\n description: 'Unique identifier for the custom metadata field. Use this to update the field.'\n },\n label: {\n type: 'string',\n description: 'Human readable name of the custom metadata field. This name is displayed as form field label to the users while setting field value on the asset in the media library UI.\\n'\n },\n name: {\n type: 'string',\n description: 'API name of the custom metadata field. This becomes the key while setting `customMetadata` (key-value object) for an asset using upload or update API.\\n'\n },\n schema: {\n type: 'object',\n description: 'An object that describes the rules for the custom metadata field value.',\n properties: {\n type: {\n type: 'string',\n description: 'Type of the custom metadata field.',\n enum: [ 'Text',\n 'Textarea',\n 'Number',\n 'Date',\n 'Boolean',\n 'SingleSelect',\n 'MultiSelect'\n ]\n },\n defaultValue: {\n anyOf: [ {\n type: 'string'\n },\n {\n type: 'number'\n },\n {\n type: 'boolean'\n },\n {\n type: 'array',\n title: 'Mixed',\n description: 'Default value should be of type array when custom metadata field type is set to `MultiSelect`.\\n',\n items: {\n anyOf: [ {\n type: 'string'\n },\n {\n type: 'number'\n },\n {\n type: 'boolean'\n }\n ]\n }\n }\n ],\n description: 'The default value for this custom metadata field. Data type of default value depends on the field type.\\n'\n },\n isValueRequired: {\n type: 'boolean',\n description: 'Specifies if the this custom metadata field is required or not.\\n'\n },\n maxLength: {\n type: 'number',\n description: 'Maximum length of string. Only set if `type` is set to `Text` or `Textarea`.\\n'\n },\n maxValue: {\n anyOf: [ {\n type: 'string'\n },\n {\n type: 'number'\n }\n ],\n description: 'Maximum value of the field. Only set if field type is `Date` or `Number`. For `Date` type field, the value will be in ISO8601 string format. For `Number` type field, it will be a numeric value.\\n'\n },\n minLength: {\n type: 'number',\n description: 'Minimum length of string. Only set if `type` is set to `Text` or `Textarea`.\\n'\n },\n minValue: {\n anyOf: [ {\n type: 'string'\n },\n {\n type: 'number'\n }\n ],\n description: 'Minimum value of the field. Only set if field type is `Date` or `Number`. For `Date` type field, the value will be in ISO8601 string format. For `Number` type field, it will be a numeric value.\\n'\n },\n selectOptions: {\n type: 'array',\n description: 'An array of allowed values when field type is `SingleSelect` or `MultiSelect`.\\n',\n items: {\n anyOf: [ {\n type: 'string'\n },\n {\n type: 'number'\n },\n {\n type: 'boolean'\n }\n ]\n }\n }\n },\n required: [ 'type'\n ]\n }\n },\n required: [ 'id',\n 'label',\n 'name',\n 'schema'\n ]\n }\n }\n}\n```",
- inputSchema: {
- type: 'object',
- properties: {
- label: {
- type: 'string',
- description:
- 'Human readable name of the custom metadata field. This should be unique across all non deleted custom metadata fields. This name is displayed as form field label to the users while setting field value on an asset in the media library UI.',
- },
- name: {
- type: 'string',
- description:
- 'API name of the custom metadata field. This should be unique across all (including deleted) custom metadata fields.',
- },
- schema: {
- type: 'object',
- properties: {
- type: {
- type: 'string',
- description: 'Type of the custom metadata field.',
- enum: ['Text', 'Textarea', 'Number', 'Date', 'Boolean', 'SingleSelect', 'MultiSelect'],
- },
- defaultValue: {
- anyOf: [
- {
- type: 'string',
- },
- {
- type: 'number',
- },
- {
- type: 'boolean',
- },
- {
- type: 'array',
- title: 'Mixed',
- description:
- 'Default value should be of type array when custom metadata field type is set to `MultiSelect`.\n',
- items: {
- anyOf: [
- {
- type: 'string',
- },
- {
- type: 'number',
- },
- {
- type: 'boolean',
- },
- ],
- },
- },
- ],
- description:
- 'The default value for this custom metadata field. This property is only required if `isValueRequired` property is set to `true`. The value should match the `type` of custom metadata field.\n',
- },
- isValueRequired: {
- type: 'boolean',
- description:
- 'Sets this custom metadata field as required. Setting custom metadata fields on an asset will throw error if the value for all required fields are not present in upload or update asset API request body.\n',
- },
- maxLength: {
- type: 'number',
- description:
- 'Maximum length of string. Only set this property if `type` is set to `Text` or `Textarea`.\n',
- },
- maxValue: {
- anyOf: [
- {
- type: 'string',
- },
- {
- type: 'number',
- },
- ],
- description:
- 'Maximum value of the field. Only set this property if field type is `Date` or `Number`. For `Date` type field, set the minimum date in ISO8601 string format. For `Number` type field, set the minimum numeric value.\n',
- },
- minLength: {
- type: 'number',
- description:
- 'Minimum length of string. Only set this property if `type` is set to `Text` or `Textarea`.\n',
- },
- minValue: {
- anyOf: [
- {
- type: 'string',
- },
- {
- type: 'number',
- },
- ],
- description:
- 'Minimum value of the field. Only set this property if field type is `Date` or `Number`. For `Date` type field, set the minimum date in ISO8601 string format. For `Number` type field, set the minimum numeric value.\n',
- },
- selectOptions: {
- type: 'array',
- description:
- 'An array of allowed values. This property is only required if `type` property is set to `SingleSelect` or `MultiSelect`.\n',
- items: {
- anyOf: [
- {
- type: 'string',
- },
- {
- type: 'number',
- },
- {
- type: 'boolean',
- },
- ],
- },
- },
- },
- required: ['type'],
- },
- jq_filter: {
- type: 'string',
- title: 'jq Filter',
- description:
- 'A jq filter to apply to the response to include certain fields. Consult the output schema in the tool description to see the fields that are available.\n\nFor example: to include only the `name` field in every object of a results array, you can provide ".results[].name".\n\nFor more information, see the [jq documentation](https://jqlang.org/manual/).',
- },
- },
- required: ['label', 'name', 'schema'],
- },
- annotations: {},
-};
-
-export const handler = async (client: ImageKit, args: Record | undefined) => {
- const { jq_filter, ...body } = args as any;
- return asTextContentResult(await maybeFilter(jq_filter, await client.customMetadataFields.create(body)));
-};
-
-export default { metadata, tool, handler };
diff --git a/packages/mcp-server/src/tools/custom-metadata-fields/delete-custom-metadata-fields.ts b/packages/mcp-server/src/tools/custom-metadata-fields/delete-custom-metadata-fields.ts
deleted file mode 100644
index f26b7b65..00000000
--- a/packages/mcp-server/src/tools/custom-metadata-fields/delete-custom-metadata-fields.ts
+++ /dev/null
@@ -1,47 +0,0 @@
-// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
-
-import { maybeFilter } from '@imagekit/api-mcp/filtering';
-import { Metadata, asTextContentResult } from '@imagekit/api-mcp/tools/types';
-
-import { Tool } from '@modelcontextprotocol/sdk/types.js';
-import ImageKit from '@imagekit/nodejs';
-
-export const metadata: Metadata = {
- resource: 'customMetadataFields',
- operation: 'write',
- tags: [],
- httpMethod: 'delete',
- httpPath: '/v1/customMetadataFields/{id}',
- operationId: 'delete-a-field',
-};
-
-export const tool: Tool = {
- name: 'delete_custom_metadata_fields',
- description:
- "When using this tool, always use the `jq_filter` parameter to reduce the response size and improve performance.\n\nOnly omit if you're sure you don't need the data.\n\nThis API deletes a custom metadata field. Even after deleting a custom metadata field, you cannot create any new custom metadata field with the same name.\n\n\n# Response Schema\n```json\n{\n type: 'object',\n properties: {}\n}\n```",
- inputSchema: {
- type: 'object',
- properties: {
- id: {
- type: 'string',
- },
- jq_filter: {
- type: 'string',
- title: 'jq Filter',
- description:
- 'A jq filter to apply to the response to include certain fields. Consult the output schema in the tool description to see the fields that are available.\n\nFor example: to include only the `name` field in every object of a results array, you can provide ".results[].name".\n\nFor more information, see the [jq documentation](https://jqlang.org/manual/).',
- },
- },
- required: ['id'],
- },
- annotations: {
- idempotentHint: true,
- },
-};
-
-export const handler = async (client: ImageKit, args: Record | undefined) => {
- const { id, jq_filter, ...body } = args as any;
- return asTextContentResult(await maybeFilter(jq_filter, await client.customMetadataFields.delete(id)));
-};
-
-export default { metadata, tool, handler };
diff --git a/packages/mcp-server/src/tools/custom-metadata-fields/list-custom-metadata-fields.ts b/packages/mcp-server/src/tools/custom-metadata-fields/list-custom-metadata-fields.ts
deleted file mode 100644
index 0367d7d1..00000000
--- a/packages/mcp-server/src/tools/custom-metadata-fields/list-custom-metadata-fields.ts
+++ /dev/null
@@ -1,53 +0,0 @@
-// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
-
-import { maybeFilter } from '@imagekit/api-mcp/filtering';
-import { Metadata, asTextContentResult } from '@imagekit/api-mcp/tools/types';
-
-import { Tool } from '@modelcontextprotocol/sdk/types.js';
-import ImageKit from '@imagekit/nodejs';
-
-export const metadata: Metadata = {
- resource: 'customMetadataFields',
- operation: 'read',
- tags: [],
- httpMethod: 'get',
- httpPath: '/v1/customMetadataFields',
- operationId: 'list-all-fields',
-};
-
-export const tool: Tool = {
- name: 'list_custom_metadata_fields',
- description:
- "When using this tool, always use the `jq_filter` parameter to reduce the response size and improve performance.\n\nOnly omit if you're sure you don't need the data.\n\nThis API returns the array of created custom metadata field objects. By default the API returns only non deleted field objects, but you can include deleted fields in the API response.\n\nYou can also filter results by a specific folder path to retrieve custom metadata fields applicable at that location. This path-specific filtering is useful when using the **Path policy** feature to determine which custom metadata fields are selected for a given path.\n\n\n# Response Schema\n```json\n{\n type: 'array',\n items: {\n $ref: '#/$defs/custom_metadata_field'\n },\n $defs: {\n custom_metadata_field: {\n type: 'object',\n description: 'Object containing details of a custom metadata field.',\n properties: {\n id: {\n type: 'string',\n description: 'Unique identifier for the custom metadata field. Use this to update the field.'\n },\n label: {\n type: 'string',\n description: 'Human readable name of the custom metadata field. This name is displayed as form field label to the users while setting field value on the asset in the media library UI.\\n'\n },\n name: {\n type: 'string',\n description: 'API name of the custom metadata field. This becomes the key while setting `customMetadata` (key-value object) for an asset using upload or update API.\\n'\n },\n schema: {\n type: 'object',\n description: 'An object that describes the rules for the custom metadata field value.',\n properties: {\n type: {\n type: 'string',\n description: 'Type of the custom metadata field.',\n enum: [ 'Text',\n 'Textarea',\n 'Number',\n 'Date',\n 'Boolean',\n 'SingleSelect',\n 'MultiSelect'\n ]\n },\n defaultValue: {\n anyOf: [ {\n type: 'string'\n },\n {\n type: 'number'\n },\n {\n type: 'boolean'\n },\n {\n type: 'array',\n title: 'Mixed',\n description: 'Default value should be of type array when custom metadata field type is set to `MultiSelect`.\\n',\n items: {\n anyOf: [ {\n type: 'string'\n },\n {\n type: 'number'\n },\n {\n type: 'boolean'\n }\n ]\n }\n }\n ],\n description: 'The default value for this custom metadata field. Data type of default value depends on the field type.\\n'\n },\n isValueRequired: {\n type: 'boolean',\n description: 'Specifies if the this custom metadata field is required or not.\\n'\n },\n maxLength: {\n type: 'number',\n description: 'Maximum length of string. Only set if `type` is set to `Text` or `Textarea`.\\n'\n },\n maxValue: {\n anyOf: [ {\n type: 'string'\n },\n {\n type: 'number'\n }\n ],\n description: 'Maximum value of the field. Only set if field type is `Date` or `Number`. For `Date` type field, the value will be in ISO8601 string format. For `Number` type field, it will be a numeric value.\\n'\n },\n minLength: {\n type: 'number',\n description: 'Minimum length of string. Only set if `type` is set to `Text` or `Textarea`.\\n'\n },\n minValue: {\n anyOf: [ {\n type: 'string'\n },\n {\n type: 'number'\n }\n ],\n description: 'Minimum value of the field. Only set if field type is `Date` or `Number`. For `Date` type field, the value will be in ISO8601 string format. For `Number` type field, it will be a numeric value.\\n'\n },\n selectOptions: {\n type: 'array',\n description: 'An array of allowed values when field type is `SingleSelect` or `MultiSelect`.\\n',\n items: {\n anyOf: [ {\n type: 'string'\n },\n {\n type: 'number'\n },\n {\n type: 'boolean'\n }\n ]\n }\n }\n },\n required: [ 'type'\n ]\n }\n },\n required: [ 'id',\n 'label',\n 'name',\n 'schema'\n ]\n }\n }\n}\n```",
- inputSchema: {
- type: 'object',
- properties: {
- folderPath: {
- type: 'string',
- description:
- 'The folder path (e.g., `/path/to/folder`) for which to retrieve applicable custom metadata fields. Useful for determining path-specific field selections when the [Path policy](https://imagekit.io/docs/dam/path-policy) feature is in use.\n',
- },
- includeDeleted: {
- type: 'boolean',
- description: 'Set it to `true` to include deleted field objects in the API response.\n',
- },
- jq_filter: {
- type: 'string',
- title: 'jq Filter',
- description:
- 'A jq filter to apply to the response to include certain fields. Consult the output schema in the tool description to see the fields that are available.\n\nFor example: to include only the `name` field in every object of a results array, you can provide ".results[].name".\n\nFor more information, see the [jq documentation](https://jqlang.org/manual/).',
- },
- },
- required: [],
- },
- annotations: {
- readOnlyHint: true,
- },
-};
-
-export const handler = async (client: ImageKit, args: Record | undefined) => {
- const { jq_filter, ...body } = args as any;
- return asTextContentResult(await maybeFilter(jq_filter, await client.customMetadataFields.list(body)));
-};
-
-export default { metadata, tool, handler };
diff --git a/packages/mcp-server/src/tools/custom-metadata-fields/update-custom-metadata-fields.ts b/packages/mcp-server/src/tools/custom-metadata-fields/update-custom-metadata-fields.ts
deleted file mode 100644
index f49b10dd..00000000
--- a/packages/mcp-server/src/tools/custom-metadata-fields/update-custom-metadata-fields.ts
+++ /dev/null
@@ -1,150 +0,0 @@
-// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
-
-import { maybeFilter } from '@imagekit/api-mcp/filtering';
-import { Metadata, asTextContentResult } from '@imagekit/api-mcp/tools/types';
-
-import { Tool } from '@modelcontextprotocol/sdk/types.js';
-import ImageKit from '@imagekit/nodejs';
-
-export const metadata: Metadata = {
- resource: 'customMetadataFields',
- operation: 'write',
- tags: [],
- httpMethod: 'patch',
- httpPath: '/v1/customMetadataFields/{id}',
- operationId: 'update-existing-field',
-};
-
-export const tool: Tool = {
- name: 'update_custom_metadata_fields',
- description:
- "When using this tool, always use the `jq_filter` parameter to reduce the response size and improve performance.\n\nOnly omit if you're sure you don't need the data.\n\nThis API updates the label or schema of an existing custom metadata field.\n\n\n# Response Schema\n```json\n{\n $ref: '#/$defs/custom_metadata_field',\n $defs: {\n custom_metadata_field: {\n type: 'object',\n description: 'Object containing details of a custom metadata field.',\n properties: {\n id: {\n type: 'string',\n description: 'Unique identifier for the custom metadata field. Use this to update the field.'\n },\n label: {\n type: 'string',\n description: 'Human readable name of the custom metadata field. This name is displayed as form field label to the users while setting field value on the asset in the media library UI.\\n'\n },\n name: {\n type: 'string',\n description: 'API name of the custom metadata field. This becomes the key while setting `customMetadata` (key-value object) for an asset using upload or update API.\\n'\n },\n schema: {\n type: 'object',\n description: 'An object that describes the rules for the custom metadata field value.',\n properties: {\n type: {\n type: 'string',\n description: 'Type of the custom metadata field.',\n enum: [ 'Text',\n 'Textarea',\n 'Number',\n 'Date',\n 'Boolean',\n 'SingleSelect',\n 'MultiSelect'\n ]\n },\n defaultValue: {\n anyOf: [ {\n type: 'string'\n },\n {\n type: 'number'\n },\n {\n type: 'boolean'\n },\n {\n type: 'array',\n title: 'Mixed',\n description: 'Default value should be of type array when custom metadata field type is set to `MultiSelect`.\\n',\n items: {\n anyOf: [ {\n type: 'string'\n },\n {\n type: 'number'\n },\n {\n type: 'boolean'\n }\n ]\n }\n }\n ],\n description: 'The default value for this custom metadata field. Data type of default value depends on the field type.\\n'\n },\n isValueRequired: {\n type: 'boolean',\n description: 'Specifies if the this custom metadata field is required or not.\\n'\n },\n maxLength: {\n type: 'number',\n description: 'Maximum length of string. Only set if `type` is set to `Text` or `Textarea`.\\n'\n },\n maxValue: {\n anyOf: [ {\n type: 'string'\n },\n {\n type: 'number'\n }\n ],\n description: 'Maximum value of the field. Only set if field type is `Date` or `Number`. For `Date` type field, the value will be in ISO8601 string format. For `Number` type field, it will be a numeric value.\\n'\n },\n minLength: {\n type: 'number',\n description: 'Minimum length of string. Only set if `type` is set to `Text` or `Textarea`.\\n'\n },\n minValue: {\n anyOf: [ {\n type: 'string'\n },\n {\n type: 'number'\n }\n ],\n description: 'Minimum value of the field. Only set if field type is `Date` or `Number`. For `Date` type field, the value will be in ISO8601 string format. For `Number` type field, it will be a numeric value.\\n'\n },\n selectOptions: {\n type: 'array',\n description: 'An array of allowed values when field type is `SingleSelect` or `MultiSelect`.\\n',\n items: {\n anyOf: [ {\n type: 'string'\n },\n {\n type: 'number'\n },\n {\n type: 'boolean'\n }\n ]\n }\n }\n },\n required: [ 'type'\n ]\n }\n },\n required: [ 'id',\n 'label',\n 'name',\n 'schema'\n ]\n }\n }\n}\n```",
- inputSchema: {
- type: 'object',
- properties: {
- id: {
- type: 'string',
- },
- label: {
- type: 'string',
- description:
- 'Human readable name of the custom metadata field. This should be unique across all non deleted custom metadata fields. This name is displayed as form field label to the users while setting field value on an asset in the media library UI. This parameter is required if `schema` is not provided.',
- },
- schema: {
- type: 'object',
- description:
- 'An object that describes the rules for the custom metadata key. This parameter is required if `label` is not provided. Note: `type` cannot be updated and will be ignored if sent with the `schema`. The schema will be validated as per the existing `type`.\n',
- properties: {
- defaultValue: {
- anyOf: [
- {
- type: 'string',
- },
- {
- type: 'number',
- },
- {
- type: 'boolean',
- },
- {
- type: 'array',
- title: 'Mixed',
- description:
- 'Default value should be of type array when custom metadata field type is set to `MultiSelect`.\n',
- items: {
- anyOf: [
- {
- type: 'string',
- },
- {
- type: 'number',
- },
- {
- type: 'boolean',
- },
- ],
- },
- },
- ],
- description:
- 'The default value for this custom metadata field. This property is only required if `isValueRequired` property is set to `true`. The value should match the `type` of custom metadata field.\n',
- },
- isValueRequired: {
- type: 'boolean',
- description:
- 'Sets this custom metadata field as required. Setting custom metadata fields on an asset will throw error if the value for all required fields are not present in upload or update asset API request body.\n',
- },
- maxLength: {
- type: 'number',
- description:
- 'Maximum length of string. Only set this property if `type` is set to `Text` or `Textarea`.\n',
- },
- maxValue: {
- anyOf: [
- {
- type: 'string',
- },
- {
- type: 'number',
- },
- ],
- description:
- 'Maximum value of the field. Only set this property if field type is `Date` or `Number`. For `Date` type field, set the minimum date in ISO8601 string format. For `Number` type field, set the minimum numeric value.\n',
- },
- minLength: {
- type: 'number',
- description:
- 'Minimum length of string. Only set this property if `type` is set to `Text` or `Textarea`.\n',
- },
- minValue: {
- anyOf: [
- {
- type: 'string',
- },
- {
- type: 'number',
- },
- ],
- description:
- 'Minimum value of the field. Only set this property if field type is `Date` or `Number`. For `Date` type field, set the minimum date in ISO8601 string format. For `Number` type field, set the minimum numeric value.\n',
- },
- selectOptions: {
- type: 'array',
- description:
- 'An array of allowed values. This property is only required if `type` property is set to `SingleSelect` or `MultiSelect`.\n',
- items: {
- anyOf: [
- {
- type: 'string',
- },
- {
- type: 'number',
- },
- {
- type: 'boolean',
- },
- ],
- },
- },
- },
- },
- jq_filter: {
- type: 'string',
- title: 'jq Filter',
- description:
- 'A jq filter to apply to the response to include certain fields. Consult the output schema in the tool description to see the fields that are available.\n\nFor example: to include only the `name` field in every object of a results array, you can provide ".results[].name".\n\nFor more information, see the [jq documentation](https://jqlang.org/manual/).',
- },
- },
- required: ['id'],
- },
- annotations: {},
-};
-
-export const handler = async (client: ImageKit, args: Record | undefined) => {
- const { id, jq_filter, ...body } = args as any;
- return asTextContentResult(
- await maybeFilter(jq_filter, await client.customMetadataFields.update(id, body)),
- );
-};
-
-export default { metadata, tool, handler };
diff --git a/packages/mcp-server/src/tools/files/bulk/add-tags-files-bulk.ts b/packages/mcp-server/src/tools/files/bulk/add-tags-files-bulk.ts
deleted file mode 100644
index 3aa9970c..00000000
--- a/packages/mcp-server/src/tools/files/bulk/add-tags-files-bulk.ts
+++ /dev/null
@@ -1,56 +0,0 @@
-// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
-
-import { maybeFilter } from '@imagekit/api-mcp/filtering';
-import { Metadata, asTextContentResult } from '@imagekit/api-mcp/tools/types';
-
-import { Tool } from '@modelcontextprotocol/sdk/types.js';
-import ImageKit from '@imagekit/nodejs';
-
-export const metadata: Metadata = {
- resource: 'files.bulk',
- operation: 'write',
- tags: [],
- httpMethod: 'post',
- httpPath: '/v1/files/addTags',
- operationId: 'add-tags-bulk',
-};
-
-export const tool: Tool = {
- name: 'add_tags_files_bulk',
- description:
- "When using this tool, always use the `jq_filter` parameter to reduce the response size and improve performance.\n\nOnly omit if you're sure you don't need the data.\n\nThis API adds tags to multiple files in bulk. A maximum of 50 files can be specified at a time.\n\n\n# Response Schema\n```json\n{\n type: 'object',\n properties: {\n successfullyUpdatedFileIds: {\n type: 'array',\n description: 'An array of fileIds that in which tags were successfully added.\\n',\n items: {\n type: 'string'\n }\n }\n }\n}\n```",
- inputSchema: {
- type: 'object',
- properties: {
- fileIds: {
- type: 'array',
- description: 'An array of fileIds to which you want to add tags.\n',
- items: {
- type: 'string',
- },
- },
- tags: {
- type: 'array',
- description: 'An array of tags that you want to add to the files.\n',
- items: {
- type: 'string',
- },
- },
- jq_filter: {
- type: 'string',
- title: 'jq Filter',
- description:
- 'A jq filter to apply to the response to include certain fields. Consult the output schema in the tool description to see the fields that are available.\n\nFor example: to include only the `name` field in every object of a results array, you can provide ".results[].name".\n\nFor more information, see the [jq documentation](https://jqlang.org/manual/).',
- },
- },
- required: ['fileIds', 'tags'],
- },
- annotations: {},
-};
-
-export const handler = async (client: ImageKit, args: Record | undefined) => {
- const { jq_filter, ...body } = args as any;
- return asTextContentResult(await maybeFilter(jq_filter, await client.files.bulk.addTags(body)));
-};
-
-export default { metadata, tool, handler };
diff --git a/packages/mcp-server/src/tools/files/bulk/delete-files-bulk.ts b/packages/mcp-server/src/tools/files/bulk/delete-files-bulk.ts
deleted file mode 100644
index 471b0c93..00000000
--- a/packages/mcp-server/src/tools/files/bulk/delete-files-bulk.ts
+++ /dev/null
@@ -1,49 +0,0 @@
-// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
-
-import { maybeFilter } from '@imagekit/api-mcp/filtering';
-import { Metadata, asTextContentResult } from '@imagekit/api-mcp/tools/types';
-
-import { Tool } from '@modelcontextprotocol/sdk/types.js';
-import ImageKit from '@imagekit/nodejs';
-
-export const metadata: Metadata = {
- resource: 'files.bulk',
- operation: 'write',
- tags: [],
- httpMethod: 'post',
- httpPath: '/v1/files/batch/deleteByFileIds',
- operationId: 'delete-multiple-files',
-};
-
-export const tool: Tool = {
- name: 'delete_files_bulk',
- description:
- "When using this tool, always use the `jq_filter` parameter to reduce the response size and improve performance.\n\nOnly omit if you're sure you don't need the data.\n\nThis API deletes multiple files and all their file versions permanently.\n\nNote: If a file or specific transformation has been requested in the past, then the response is cached. Deleting a file does not purge the cache. You can purge the cache using purge cache API.\n\nA maximum of 100 files can be deleted at a time.\n\n\n# Response Schema\n```json\n{\n type: 'object',\n properties: {\n successfullyDeletedFileIds: {\n type: 'array',\n description: 'An array of fileIds that were successfully deleted.\\n',\n items: {\n type: 'string'\n }\n }\n }\n}\n```",
- inputSchema: {
- type: 'object',
- properties: {
- fileIds: {
- type: 'array',
- description: 'An array of fileIds which you want to delete.\n',
- items: {
- type: 'string',
- },
- },
- jq_filter: {
- type: 'string',
- title: 'jq Filter',
- description:
- 'A jq filter to apply to the response to include certain fields. Consult the output schema in the tool description to see the fields that are available.\n\nFor example: to include only the `name` field in every object of a results array, you can provide ".results[].name".\n\nFor more information, see the [jq documentation](https://jqlang.org/manual/).',
- },
- },
- required: ['fileIds'],
- },
- annotations: {},
-};
-
-export const handler = async (client: ImageKit, args: Record | undefined) => {
- const { jq_filter, ...body } = args as any;
- return asTextContentResult(await maybeFilter(jq_filter, await client.files.bulk.delete(body)));
-};
-
-export default { metadata, tool, handler };
diff --git a/packages/mcp-server/src/tools/files/bulk/remove-ai-tags-files-bulk.ts b/packages/mcp-server/src/tools/files/bulk/remove-ai-tags-files-bulk.ts
deleted file mode 100644
index 28ea4b62..00000000
--- a/packages/mcp-server/src/tools/files/bulk/remove-ai-tags-files-bulk.ts
+++ /dev/null
@@ -1,56 +0,0 @@
-// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
-
-import { maybeFilter } from '@imagekit/api-mcp/filtering';
-import { Metadata, asTextContentResult } from '@imagekit/api-mcp/tools/types';
-
-import { Tool } from '@modelcontextprotocol/sdk/types.js';
-import ImageKit from '@imagekit/nodejs';
-
-export const metadata: Metadata = {
- resource: 'files.bulk',
- operation: 'write',
- tags: [],
- httpMethod: 'post',
- httpPath: '/v1/files/removeAITags',
- operationId: 'remove-ai-tags-bulk',
-};
-
-export const tool: Tool = {
- name: 'remove_ai_tags_files_bulk',
- description:
- "When using this tool, always use the `jq_filter` parameter to reduce the response size and improve performance.\n\nOnly omit if you're sure you don't need the data.\n\nThis API removes AITags from multiple files in bulk. A maximum of 50 files can be specified at a time.\n\n\n# Response Schema\n```json\n{\n type: 'object',\n properties: {\n successfullyUpdatedFileIds: {\n type: 'array',\n description: 'An array of fileIds that in which AITags were successfully removed.\\n',\n items: {\n type: 'string'\n }\n }\n }\n}\n```",
- inputSchema: {
- type: 'object',
- properties: {
- AITags: {
- type: 'array',
- description: 'An array of AITags that you want to remove from the files.\n',
- items: {
- type: 'string',
- },
- },
- fileIds: {
- type: 'array',
- description: 'An array of fileIds from which you want to remove AITags.\n',
- items: {
- type: 'string',
- },
- },
- jq_filter: {
- type: 'string',
- title: 'jq Filter',
- description:
- 'A jq filter to apply to the response to include certain fields. Consult the output schema in the tool description to see the fields that are available.\n\nFor example: to include only the `name` field in every object of a results array, you can provide ".results[].name".\n\nFor more information, see the [jq documentation](https://jqlang.org/manual/).',
- },
- },
- required: ['AITags', 'fileIds'],
- },
- annotations: {},
-};
-
-export const handler = async (client: ImageKit, args: Record | undefined) => {
- const { jq_filter, ...body } = args as any;
- return asTextContentResult(await maybeFilter(jq_filter, await client.files.bulk.removeAITags(body)));
-};
-
-export default { metadata, tool, handler };
diff --git a/packages/mcp-server/src/tools/files/bulk/remove-tags-files-bulk.ts b/packages/mcp-server/src/tools/files/bulk/remove-tags-files-bulk.ts
deleted file mode 100644
index 2fd2661e..00000000
--- a/packages/mcp-server/src/tools/files/bulk/remove-tags-files-bulk.ts
+++ /dev/null
@@ -1,56 +0,0 @@
-// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
-
-import { maybeFilter } from '@imagekit/api-mcp/filtering';
-import { Metadata, asTextContentResult } from '@imagekit/api-mcp/tools/types';
-
-import { Tool } from '@modelcontextprotocol/sdk/types.js';
-import ImageKit from '@imagekit/nodejs';
-
-export const metadata: Metadata = {
- resource: 'files.bulk',
- operation: 'write',
- tags: [],
- httpMethod: 'post',
- httpPath: '/v1/files/removeTags',
- operationId: 'remove-tags-bulk',
-};
-
-export const tool: Tool = {
- name: 'remove_tags_files_bulk',
- description:
- "When using this tool, always use the `jq_filter` parameter to reduce the response size and improve performance.\n\nOnly omit if you're sure you don't need the data.\n\nThis API removes tags from multiple files in bulk. A maximum of 50 files can be specified at a time.\n\n\n# Response Schema\n```json\n{\n type: 'object',\n properties: {\n successfullyUpdatedFileIds: {\n type: 'array',\n description: 'An array of fileIds that in which tags were successfully removed.\\n',\n items: {\n type: 'string'\n }\n }\n }\n}\n```",
- inputSchema: {
- type: 'object',
- properties: {
- fileIds: {
- type: 'array',
- description: 'An array of fileIds from which you want to remove tags.\n',
- items: {
- type: 'string',
- },
- },
- tags: {
- type: 'array',
- description: 'An array of tags that you want to remove from the files.\n',
- items: {
- type: 'string',
- },
- },
- jq_filter: {
- type: 'string',
- title: 'jq Filter',
- description:
- 'A jq filter to apply to the response to include certain fields. Consult the output schema in the tool description to see the fields that are available.\n\nFor example: to include only the `name` field in every object of a results array, you can provide ".results[].name".\n\nFor more information, see the [jq documentation](https://jqlang.org/manual/).',
- },
- },
- required: ['fileIds', 'tags'],
- },
- annotations: {},
-};
-
-export const handler = async (client: ImageKit, args: Record | undefined) => {
- const { jq_filter, ...body } = args as any;
- return asTextContentResult(await maybeFilter(jq_filter, await client.files.bulk.removeTags(body)));
-};
-
-export default { metadata, tool, handler };
diff --git a/packages/mcp-server/src/tools/files/copy-files.ts b/packages/mcp-server/src/tools/files/copy-files.ts
deleted file mode 100644
index 6dffab77..00000000
--- a/packages/mcp-server/src/tools/files/copy-files.ts
+++ /dev/null
@@ -1,55 +0,0 @@
-// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
-
-import { maybeFilter } from '@imagekit/api-mcp/filtering';
-import { Metadata, asTextContentResult } from '@imagekit/api-mcp/tools/types';
-
-import { Tool } from '@modelcontextprotocol/sdk/types.js';
-import ImageKit from '@imagekit/nodejs';
-
-export const metadata: Metadata = {
- resource: 'files',
- operation: 'write',
- tags: [],
- httpMethod: 'post',
- httpPath: '/v1/files/copy',
- operationId: 'copy-file',
-};
-
-export const tool: Tool = {
- name: 'copy_files',
- description:
- "When using this tool, always use the `jq_filter` parameter to reduce the response size and improve performance.\n\nOnly omit if you're sure you don't need the data.\n\nThis will copy a file from one folder to another. \n\nNote: If any file at the destination has the same name as the source file, then the source file and its versions (if `includeFileVersions` is set to true) will be appended to the destination file version history.\n\n\n# Response Schema\n```json\n{\n type: 'object',\n properties: {}\n}\n```",
- inputSchema: {
- type: 'object',
- properties: {
- destinationPath: {
- type: 'string',
- description: 'Full path to the folder you want to copy the above file into.\n',
- },
- sourceFilePath: {
- type: 'string',
- description: 'The full path of the file you want to copy.\n',
- },
- includeFileVersions: {
- type: 'boolean',
- description:
- 'Option to copy all versions of a file. By default, only the current version of the file is copied. When set to true, all versions of the file will be copied. Default value - `false`.\n',
- },
- jq_filter: {
- type: 'string',
- title: 'jq Filter',
- description:
- 'A jq filter to apply to the response to include certain fields. Consult the output schema in the tool description to see the fields that are available.\n\nFor example: to include only the `name` field in every object of a results array, you can provide ".results[].name".\n\nFor more information, see the [jq documentation](https://jqlang.org/manual/).',
- },
- },
- required: ['destinationPath', 'sourceFilePath'],
- },
- annotations: {},
-};
-
-export const handler = async (client: ImageKit, args: Record | undefined) => {
- const { jq_filter, ...body } = args as any;
- return asTextContentResult(await maybeFilter(jq_filter, await client.files.copy(body)));
-};
-
-export default { metadata, tool, handler };
diff --git a/packages/mcp-server/src/tools/files/delete-files.ts b/packages/mcp-server/src/tools/files/delete-files.ts
deleted file mode 100644
index dac67c16..00000000
--- a/packages/mcp-server/src/tools/files/delete-files.ts
+++ /dev/null
@@ -1,41 +0,0 @@
-// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
-
-import { Metadata, asTextContentResult } from '@imagekit/api-mcp/tools/types';
-
-import { Tool } from '@modelcontextprotocol/sdk/types.js';
-import ImageKit from '@imagekit/nodejs';
-
-export const metadata: Metadata = {
- resource: 'files',
- operation: 'write',
- tags: [],
- httpMethod: 'delete',
- httpPath: '/v1/files/{fileId}',
- operationId: 'delete-file',
-};
-
-export const tool: Tool = {
- name: 'delete_files',
- description:
- 'This API deletes the file and all its file versions permanently.\n\nNote: If a file or specific transformation has been requested in the past, then the response is cached. Deleting a file does not purge the cache. You can purge the cache using purge cache API.\n',
- inputSchema: {
- type: 'object',
- properties: {
- fileId: {
- type: 'string',
- },
- },
- required: ['fileId'],
- },
- annotations: {
- idempotentHint: true,
- },
-};
-
-export const handler = async (client: ImageKit, args: Record | undefined) => {
- const { fileId, ...body } = args as any;
- const response = await client.files.delete(fileId).asResponse();
- return asTextContentResult(await response.text());
-};
-
-export default { metadata, tool, handler };
diff --git a/packages/mcp-server/src/tools/files/get-files.ts b/packages/mcp-server/src/tools/files/get-files.ts
deleted file mode 100644
index 958ab961..00000000
--- a/packages/mcp-server/src/tools/files/get-files.ts
+++ /dev/null
@@ -1,47 +0,0 @@
-// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
-
-import { maybeFilter } from '@imagekit/api-mcp/filtering';
-import { Metadata, asTextContentResult } from '@imagekit/api-mcp/tools/types';
-
-import { Tool } from '@modelcontextprotocol/sdk/types.js';
-import ImageKit from '@imagekit/nodejs';
-
-export const metadata: Metadata = {
- resource: 'files',
- operation: 'read',
- tags: [],
- httpMethod: 'get',
- httpPath: '/v1/files/{fileId}/details',
- operationId: 'get-file-details',
-};
-
-export const tool: Tool = {
- name: 'get_files',
- description:
- "When using this tool, always use the `jq_filter` parameter to reduce the response size and improve performance.\n\nOnly omit if you're sure you don't need the data.\n\nThis API returns an object with details or attributes about the current version of the file.\n\n# Response Schema\n```json\n{\n $ref: '#/$defs/file',\n $defs: {\n file: {\n type: 'object',\n title: 'File & File Version',\n description: 'Object containing details of a file or file version.',\n properties: {\n AITags: {\n type: 'array',\n description: 'An array of tags assigned to the file by auto tagging.\\n',\n items: {\n type: 'object',\n properties: {\n confidence: {\n type: 'number',\n description: 'Confidence score of the tag.'\n },\n name: {\n type: 'string',\n description: 'Name of the tag.'\n },\n source: {\n type: 'string',\n description: 'Source of the tag. Possible values are `google-auto-tagging` and `aws-auto-tagging`.'\n }\n }\n }\n },\n createdAt: {\n type: 'string',\n description: 'Date and time when the file was uploaded. The date and time is in ISO8601 format.\\n',\n format: 'date-time'\n },\n customCoordinates: {\n type: 'string',\n description: 'An string with custom coordinates of the file.\\n'\n },\n customMetadata: {\n type: 'object',\n description: 'An object with custom metadata for the file.\\n',\n additionalProperties: true\n },\n description: {\n type: 'string',\n description: 'Optional text to describe the contents of the file. Can be set by the user or the ai-auto-description extension.\\n'\n },\n fileId: {\n type: 'string',\n description: 'Unique identifier of the asset.'\n },\n filePath: {\n type: 'string',\n description: 'Path of the file. This is the path you would use in the URL to access the file. For example, if the file is at the root of the media library, the path will be `/file.jpg`. If the file is inside a folder named `images`, the path will be `/images/file.jpg`.\\n'\n },\n fileType: {\n type: 'string',\n description: 'Type of the file. Possible values are `image`, `non-image`.\\n'\n },\n hasAlpha: {\n type: 'boolean',\n description: 'Specifies if the image has an alpha channel.\\n'\n },\n height: {\n type: 'number',\n description: 'Height of the file.\\n'\n },\n isPrivateFile: {\n type: 'boolean',\n description: 'Specifies if the file is private or not.\\n'\n },\n isPublished: {\n type: 'boolean',\n description: 'Specifies if the file is published or not.\\n'\n },\n mime: {\n type: 'string',\n description: 'MIME type of the file.\\n'\n },\n name: {\n type: 'string',\n description: 'Name of the asset.'\n },\n selectedFieldsSchema: {\n type: 'object',\n description: 'This field is included in the response only if the Path policy feature is available in the plan.\\nIt contains schema definitions for the custom metadata fields selected for the specified file path.\\nField selection can only be done when the Path policy feature is enabled.\\n\\nKeys are the names of the custom metadata fields; the value object has details about the custom metadata schema.\\n',\n additionalProperties: true\n },\n size: {\n type: 'number',\n description: 'Size of the file in bytes.\\n'\n },\n tags: {\n type: 'array',\n description: 'An array of tags assigned to the file. Tags are used to search files in the media library.\\n',\n items: {\n type: 'string'\n }\n },\n thumbnail: {\n type: 'string',\n description: 'URL of the thumbnail image. This URL is used to access the thumbnail image of the file in the media library.\\n'\n },\n type: {\n type: 'string',\n description: 'Type of the asset.',\n enum: [ 'file',\n 'file-version'\n ]\n },\n updatedAt: {\n type: 'string',\n description: 'Date and time when the file was last updated. The date and time is in ISO8601 format.\\n',\n format: 'date-time'\n },\n url: {\n type: 'string',\n description: 'URL of the file.\\n'\n },\n versionInfo: {\n type: 'object',\n description: 'An object with details of the file version.\\n',\n properties: {\n id: {\n type: 'string',\n description: 'Unique identifier of the file version.'\n },\n name: {\n type: 'string',\n description: 'Name of the file version.'\n }\n }\n },\n width: {\n type: 'number',\n description: 'Width of the file.\\n'\n }\n }\n }\n }\n}\n```",
- inputSchema: {
- type: 'object',
- properties: {
- fileId: {
- type: 'string',
- },
- jq_filter: {
- type: 'string',
- title: 'jq Filter',
- description:
- 'A jq filter to apply to the response to include certain fields. Consult the output schema in the tool description to see the fields that are available.\n\nFor example: to include only the `name` field in every object of a results array, you can provide ".results[].name".\n\nFor more information, see the [jq documentation](https://jqlang.org/manual/).',
- },
- },
- required: ['fileId'],
- },
- annotations: {
- readOnlyHint: true,
- },
-};
-
-export const handler = async (client: ImageKit, args: Record | undefined) => {
- const { fileId, jq_filter, ...body } = args as any;
- return asTextContentResult(await maybeFilter(jq_filter, await client.files.get(fileId)));
-};
-
-export default { metadata, tool, handler };
diff --git a/packages/mcp-server/src/tools/files/metadata/get-files-metadata.ts b/packages/mcp-server/src/tools/files/metadata/get-files-metadata.ts
deleted file mode 100644
index 04cf9ad4..00000000
--- a/packages/mcp-server/src/tools/files/metadata/get-files-metadata.ts
+++ /dev/null
@@ -1,47 +0,0 @@
-// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
-
-import { maybeFilter } from '@imagekit/api-mcp/filtering';
-import { Metadata, asTextContentResult } from '@imagekit/api-mcp/tools/types';
-
-import { Tool } from '@modelcontextprotocol/sdk/types.js';
-import ImageKit from '@imagekit/nodejs';
-
-export const metadata: Metadata = {
- resource: 'files.metadata',
- operation: 'read',
- tags: [],
- httpMethod: 'get',
- httpPath: '/v1/files/{fileId}/metadata',
- operationId: 'get-uploaded-file-metadata',
-};
-
-export const tool: Tool = {
- name: 'get_files_metadata',
- description:
- "When using this tool, always use the `jq_filter` parameter to reduce the response size and improve performance.\n\nOnly omit if you're sure you don't need the data.\n\nYou can programmatically get image EXIF, pHash, and other metadata for uploaded files in the ImageKit.io media library using this API.\n\nYou can also get the metadata in upload API response by passing `metadata` in `responseFields` parameter.\n\n\n# Response Schema\n```json\n{\n $ref: '#/$defs/metadata',\n $defs: {\n metadata: {\n type: 'object',\n description: 'JSON object containing metadata.',\n properties: {\n audioCodec: {\n type: 'string',\n description: 'The audio codec used in the video (only for video).'\n },\n bitRate: {\n type: 'integer',\n description: 'The bit rate of the video in kbps (only for video).'\n },\n density: {\n type: 'integer',\n description: 'The density of the image in DPI.'\n },\n duration: {\n type: 'integer',\n description: 'The duration of the video in seconds (only for video).'\n },\n exif: {\n type: 'object',\n properties: {\n exif: {\n type: 'object',\n description: 'Object containing Exif details.',\n properties: {\n ApertureValue: {\n type: 'number'\n },\n ColorSpace: {\n type: 'integer'\n },\n CreateDate: {\n type: 'string'\n },\n CustomRendered: {\n type: 'integer'\n },\n DateTimeOriginal: {\n type: 'string'\n },\n ExifImageHeight: {\n type: 'integer'\n },\n ExifImageWidth: {\n type: 'integer'\n },\n ExifVersion: {\n type: 'string'\n },\n ExposureCompensation: {\n type: 'number'\n },\n ExposureMode: {\n type: 'integer'\n },\n ExposureProgram: {\n type: 'integer'\n },\n ExposureTime: {\n type: 'number'\n },\n Flash: {\n type: 'integer'\n },\n FlashpixVersion: {\n type: 'string'\n },\n FNumber: {\n type: 'number'\n },\n FocalLength: {\n type: 'integer'\n },\n FocalPlaneResolutionUnit: {\n type: 'integer'\n },\n FocalPlaneXResolution: {\n type: 'number'\n },\n FocalPlaneYResolution: {\n type: 'number'\n },\n InteropOffset: {\n type: 'integer'\n },\n ISO: {\n type: 'integer'\n },\n MeteringMode: {\n type: 'integer'\n },\n SceneCaptureType: {\n type: 'integer'\n },\n ShutterSpeedValue: {\n type: 'number'\n },\n SubSecTime: {\n type: 'string'\n },\n WhiteBalance: {\n type: 'integer'\n }\n }\n },\n gps: {\n type: 'object',\n description: 'Object containing GPS information.',\n properties: {\n GPSVersionID: {\n type: 'array',\n items: {\n type: 'integer'\n }\n }\n }\n },\n image: {\n type: 'object',\n description: 'Object containing EXIF image information.',\n properties: {\n ExifOffset: {\n type: 'integer'\n },\n GPSInfo: {\n type: 'integer'\n },\n Make: {\n type: 'string'\n },\n Model: {\n type: 'string'\n },\n ModifyDate: {\n type: 'string'\n },\n Orientation: {\n type: 'integer'\n },\n ResolutionUnit: {\n type: 'integer'\n },\n Software: {\n type: 'string'\n },\n XResolution: {\n type: 'integer'\n },\n YCbCrPositioning: {\n type: 'integer'\n },\n YResolution: {\n type: 'integer'\n }\n }\n },\n interoperability: {\n type: 'object',\n description: 'JSON object.',\n properties: {\n InteropIndex: {\n type: 'string'\n },\n InteropVersion: {\n type: 'string'\n }\n }\n },\n makernote: {\n type: 'object',\n additionalProperties: true\n },\n thumbnail: {\n type: 'object',\n description: 'Object containing Thumbnail information.',\n properties: {\n Compression: {\n type: 'integer'\n },\n ResolutionUnit: {\n type: 'integer'\n },\n ThumbnailLength: {\n type: 'integer'\n },\n ThumbnailOffset: {\n type: 'integer'\n },\n XResolution: {\n type: 'integer'\n },\n YResolution: {\n type: 'integer'\n }\n }\n }\n }\n },\n format: {\n type: 'string',\n description: 'The format of the file (e.g., \\'jpg\\', \\'mp4\\').'\n },\n hasColorProfile: {\n type: 'boolean',\n description: 'Indicates if the image has a color profile.'\n },\n hasTransparency: {\n type: 'boolean',\n description: 'Indicates if the image contains transparent areas.'\n },\n height: {\n type: 'integer',\n description: 'The height of the image or video in pixels.'\n },\n pHash: {\n type: 'string',\n description: 'Perceptual hash of the image.'\n },\n quality: {\n type: 'integer',\n description: 'The quality indicator of the image.'\n },\n size: {\n type: 'integer',\n description: 'The file size in bytes.'\n },\n videoCodec: {\n type: 'string',\n description: 'The video codec used in the video (only for video).'\n },\n width: {\n type: 'integer',\n description: 'The width of the image or video in pixels.'\n }\n }\n }\n }\n}\n```",
- inputSchema: {
- type: 'object',
- properties: {
- fileId: {
- type: 'string',
- },
- jq_filter: {
- type: 'string',
- title: 'jq Filter',
- description:
- 'A jq filter to apply to the response to include certain fields. Consult the output schema in the tool description to see the fields that are available.\n\nFor example: to include only the `name` field in every object of a results array, you can provide ".results[].name".\n\nFor more information, see the [jq documentation](https://jqlang.org/manual/).',
- },
- },
- required: ['fileId'],
- },
- annotations: {
- readOnlyHint: true,
- },
-};
-
-export const handler = async (client: ImageKit, args: Record | undefined) => {
- const { fileId, jq_filter, ...body } = args as any;
- return asTextContentResult(await maybeFilter(jq_filter, await client.files.metadata.get(fileId)));
-};
-
-export default { metadata, tool, handler };
diff --git a/packages/mcp-server/src/tools/files/metadata/get-from-url-files-metadata.ts b/packages/mcp-server/src/tools/files/metadata/get-from-url-files-metadata.ts
deleted file mode 100644
index 08ec83c9..00000000
--- a/packages/mcp-server/src/tools/files/metadata/get-from-url-files-metadata.ts
+++ /dev/null
@@ -1,48 +0,0 @@
-// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
-
-import { maybeFilter } from '@imagekit/api-mcp/filtering';
-import { Metadata, asTextContentResult } from '@imagekit/api-mcp/tools/types';
-
-import { Tool } from '@modelcontextprotocol/sdk/types.js';
-import ImageKit from '@imagekit/nodejs';
-
-export const metadata: Metadata = {
- resource: 'files.metadata',
- operation: 'read',
- tags: [],
- httpMethod: 'get',
- httpPath: '/v1/files/metadata',
- operationId: 'get-metadata-from-url',
-};
-
-export const tool: Tool = {
- name: 'get_from_url_files_metadata',
- description:
- "When using this tool, always use the `jq_filter` parameter to reduce the response size and improve performance.\n\nOnly omit if you're sure you don't need the data.\n\nGet image EXIF, pHash, and other metadata from ImageKit.io powered remote URL using this API.\n\n\n# Response Schema\n```json\n{\n $ref: '#/$defs/metadata',\n $defs: {\n metadata: {\n type: 'object',\n description: 'JSON object containing metadata.',\n properties: {\n audioCodec: {\n type: 'string',\n description: 'The audio codec used in the video (only for video).'\n },\n bitRate: {\n type: 'integer',\n description: 'The bit rate of the video in kbps (only for video).'\n },\n density: {\n type: 'integer',\n description: 'The density of the image in DPI.'\n },\n duration: {\n type: 'integer',\n description: 'The duration of the video in seconds (only for video).'\n },\n exif: {\n type: 'object',\n properties: {\n exif: {\n type: 'object',\n description: 'Object containing Exif details.',\n properties: {\n ApertureValue: {\n type: 'number'\n },\n ColorSpace: {\n type: 'integer'\n },\n CreateDate: {\n type: 'string'\n },\n CustomRendered: {\n type: 'integer'\n },\n DateTimeOriginal: {\n type: 'string'\n },\n ExifImageHeight: {\n type: 'integer'\n },\n ExifImageWidth: {\n type: 'integer'\n },\n ExifVersion: {\n type: 'string'\n },\n ExposureCompensation: {\n type: 'number'\n },\n ExposureMode: {\n type: 'integer'\n },\n ExposureProgram: {\n type: 'integer'\n },\n ExposureTime: {\n type: 'number'\n },\n Flash: {\n type: 'integer'\n },\n FlashpixVersion: {\n type: 'string'\n },\n FNumber: {\n type: 'number'\n },\n FocalLength: {\n type: 'integer'\n },\n FocalPlaneResolutionUnit: {\n type: 'integer'\n },\n FocalPlaneXResolution: {\n type: 'number'\n },\n FocalPlaneYResolution: {\n type: 'number'\n },\n InteropOffset: {\n type: 'integer'\n },\n ISO: {\n type: 'integer'\n },\n MeteringMode: {\n type: 'integer'\n },\n SceneCaptureType: {\n type: 'integer'\n },\n ShutterSpeedValue: {\n type: 'number'\n },\n SubSecTime: {\n type: 'string'\n },\n WhiteBalance: {\n type: 'integer'\n }\n }\n },\n gps: {\n type: 'object',\n description: 'Object containing GPS information.',\n properties: {\n GPSVersionID: {\n type: 'array',\n items: {\n type: 'integer'\n }\n }\n }\n },\n image: {\n type: 'object',\n description: 'Object containing EXIF image information.',\n properties: {\n ExifOffset: {\n type: 'integer'\n },\n GPSInfo: {\n type: 'integer'\n },\n Make: {\n type: 'string'\n },\n Model: {\n type: 'string'\n },\n ModifyDate: {\n type: 'string'\n },\n Orientation: {\n type: 'integer'\n },\n ResolutionUnit: {\n type: 'integer'\n },\n Software: {\n type: 'string'\n },\n XResolution: {\n type: 'integer'\n },\n YCbCrPositioning: {\n type: 'integer'\n },\n YResolution: {\n type: 'integer'\n }\n }\n },\n interoperability: {\n type: 'object',\n description: 'JSON object.',\n properties: {\n InteropIndex: {\n type: 'string'\n },\n InteropVersion: {\n type: 'string'\n }\n }\n },\n makernote: {\n type: 'object',\n additionalProperties: true\n },\n thumbnail: {\n type: 'object',\n description: 'Object containing Thumbnail information.',\n properties: {\n Compression: {\n type: 'integer'\n },\n ResolutionUnit: {\n type: 'integer'\n },\n ThumbnailLength: {\n type: 'integer'\n },\n ThumbnailOffset: {\n type: 'integer'\n },\n XResolution: {\n type: 'integer'\n },\n YResolution: {\n type: 'integer'\n }\n }\n }\n }\n },\n format: {\n type: 'string',\n description: 'The format of the file (e.g., \\'jpg\\', \\'mp4\\').'\n },\n hasColorProfile: {\n type: 'boolean',\n description: 'Indicates if the image has a color profile.'\n },\n hasTransparency: {\n type: 'boolean',\n description: 'Indicates if the image contains transparent areas.'\n },\n height: {\n type: 'integer',\n description: 'The height of the image or video in pixels.'\n },\n pHash: {\n type: 'string',\n description: 'Perceptual hash of the image.'\n },\n quality: {\n type: 'integer',\n description: 'The quality indicator of the image.'\n },\n size: {\n type: 'integer',\n description: 'The file size in bytes.'\n },\n videoCodec: {\n type: 'string',\n description: 'The video codec used in the video (only for video).'\n },\n width: {\n type: 'integer',\n description: 'The width of the image or video in pixels.'\n }\n }\n }\n }\n}\n```",
- inputSchema: {
- type: 'object',
- properties: {
- url: {
- type: 'string',
- description: 'Should be a valid file URL. It should be accessible using your ImageKit.io account.\n',
- },
- jq_filter: {
- type: 'string',
- title: 'jq Filter',
- description:
- 'A jq filter to apply to the response to include certain fields. Consult the output schema in the tool description to see the fields that are available.\n\nFor example: to include only the `name` field in every object of a results array, you can provide ".results[].name".\n\nFor more information, see the [jq documentation](https://jqlang.org/manual/).',
- },
- },
- required: ['url'],
- },
- annotations: {
- readOnlyHint: true,
- },
-};
-
-export const handler = async (client: ImageKit, args: Record | undefined) => {
- const { jq_filter, ...body } = args as any;
- return asTextContentResult(await maybeFilter(jq_filter, await client.files.metadata.getFromURL(body)));
-};
-
-export default { metadata, tool, handler };
diff --git a/packages/mcp-server/src/tools/files/move-files.ts b/packages/mcp-server/src/tools/files/move-files.ts
deleted file mode 100644
index 48c159a2..00000000
--- a/packages/mcp-server/src/tools/files/move-files.ts
+++ /dev/null
@@ -1,50 +0,0 @@
-// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
-
-import { maybeFilter } from '@imagekit/api-mcp/filtering';
-import { Metadata, asTextContentResult } from '@imagekit/api-mcp/tools/types';
-
-import { Tool } from '@modelcontextprotocol/sdk/types.js';
-import ImageKit from '@imagekit/nodejs';
-
-export const metadata: Metadata = {
- resource: 'files',
- operation: 'write',
- tags: [],
- httpMethod: 'post',
- httpPath: '/v1/files/move',
- operationId: 'move-file',
-};
-
-export const tool: Tool = {
- name: 'move_files',
- description:
- "When using this tool, always use the `jq_filter` parameter to reduce the response size and improve performance.\n\nOnly omit if you're sure you don't need the data.\n\nThis will move a file and all its versions from one folder to another. \n\nNote: If any file at the destination has the same name as the source file, then the source file and its versions will be appended to the destination file.\n\n\n# Response Schema\n```json\n{\n type: 'object',\n properties: {}\n}\n```",
- inputSchema: {
- type: 'object',
- properties: {
- destinationPath: {
- type: 'string',
- description: 'Full path to the folder you want to move the above file into.\n',
- },
- sourceFilePath: {
- type: 'string',
- description: 'The full path of the file you want to move.\n',
- },
- jq_filter: {
- type: 'string',
- title: 'jq Filter',
- description:
- 'A jq filter to apply to the response to include certain fields. Consult the output schema in the tool description to see the fields that are available.\n\nFor example: to include only the `name` field in every object of a results array, you can provide ".results[].name".\n\nFor more information, see the [jq documentation](https://jqlang.org/manual/).',
- },
- },
- required: ['destinationPath', 'sourceFilePath'],
- },
- annotations: {},
-};
-
-export const handler = async (client: ImageKit, args: Record | undefined) => {
- const { jq_filter, ...body } = args as any;
- return asTextContentResult(await maybeFilter(jq_filter, await client.files.move(body)));
-};
-
-export default { metadata, tool, handler };
diff --git a/packages/mcp-server/src/tools/files/rename-files.ts b/packages/mcp-server/src/tools/files/rename-files.ts
deleted file mode 100644
index 2e76c956..00000000
--- a/packages/mcp-server/src/tools/files/rename-files.ts
+++ /dev/null
@@ -1,58 +0,0 @@
-// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
-
-import { maybeFilter } from '@imagekit/api-mcp/filtering';
-import { Metadata, asTextContentResult } from '@imagekit/api-mcp/tools/types';
-
-import { Tool } from '@modelcontextprotocol/sdk/types.js';
-import ImageKit from '@imagekit/nodejs';
-
-export const metadata: Metadata = {
- resource: 'files',
- operation: 'write',
- tags: [],
- httpMethod: 'put',
- httpPath: '/v1/files/rename',
- operationId: 'rename-file',
-};
-
-export const tool: Tool = {
- name: 'rename_files',
- description:
- "When using this tool, always use the `jq_filter` parameter to reduce the response size and improve performance.\n\nOnly omit if you're sure you don't need the data.\n\nYou can rename an already existing file in the media library using rename file API. This operation would rename all file versions of the file. \n\nNote: The old URLs will stop working. The file/file version URLs cached on CDN will continue to work unless a purge is requested.\n\n\n# Response Schema\n```json\n{\n type: 'object',\n properties: {\n purgeRequestId: {\n type: 'string',\n description: 'Unique identifier of the purge request. This can be used to check the status of the purge request.\\n'\n }\n }\n}\n```",
- inputSchema: {
- type: 'object',
- properties: {
- filePath: {
- type: 'string',
- description: 'The full path of the file you want to rename.\n',
- },
- newFileName: {
- type: 'string',
- description:
- 'The new name of the file. A filename can contain:\n\nAlphanumeric Characters: `a-z`, `A-Z`, `0-9` (including Unicode letters, marks, and numerals in other languages).\nSpecial Characters: `.`, `_`, and `-`.\n\nAny other character, including space, will be replaced by `_`.\n',
- },
- purgeCache: {
- type: 'boolean',
- description:
- "Option to purge cache for the old file and its versions' URLs.\n\nWhen set to true, it will internally issue a purge cache request on CDN to remove cached content of old file and its versions. This purge request is counted against your monthly purge quota.\n\nNote: If the old file were accessible at `https://ik.imagekit.io/demo/old-filename.jpg`, a purge cache request would be issued against `https://ik.imagekit.io/demo/old-filename.jpg*` (with a wildcard at the end). It will remove the file and its versions' URLs and any transformations made using query parameters on this file or its versions. However, the cache for file transformations made using path parameters will persist. You can purge them using the purge API. For more details, refer to the purge API documentation.\n\n\n\nDefault value - `false`\n",
- },
- jq_filter: {
- type: 'string',
- title: 'jq Filter',
- description:
- 'A jq filter to apply to the response to include certain fields. Consult the output schema in the tool description to see the fields that are available.\n\nFor example: to include only the `name` field in every object of a results array, you can provide ".results[].name".\n\nFor more information, see the [jq documentation](https://jqlang.org/manual/).',
- },
- },
- required: ['filePath', 'newFileName'],
- },
- annotations: {
- idempotentHint: true,
- },
-};
-
-export const handler = async (client: ImageKit, args: Record | undefined) => {
- const { jq_filter, ...body } = args as any;
- return asTextContentResult(await maybeFilter(jq_filter, await client.files.rename(body)));
-};
-
-export default { metadata, tool, handler };
diff --git a/packages/mcp-server/src/tools/files/update-files.ts b/packages/mcp-server/src/tools/files/update-files.ts
deleted file mode 100644
index e21194ca..00000000
--- a/packages/mcp-server/src/tools/files/update-files.ts
+++ /dev/null
@@ -1,196 +0,0 @@
-// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
-
-import { Metadata, asTextContentResult } from '@imagekit/api-mcp/tools/types';
-
-import { Tool } from '@modelcontextprotocol/sdk/types.js';
-import ImageKit from '@imagekit/nodejs';
-
-export const metadata: Metadata = {
- resource: 'files',
- operation: 'write',
- tags: [],
- httpMethod: 'patch',
- httpPath: '/v1/files/{fileId}/details',
- operationId: 'update-file-details',
-};
-
-export const tool: Tool = {
- name: 'update_files',
- description:
- 'This API updates the details or attributes of the current version of the file. You can update `tags`, `customCoordinates`, `customMetadata`, publication status, remove existing `AITags` and apply extensions using this API.\n',
- inputSchema: {
- type: 'object',
- anyOf: [
- {
- type: 'object',
- properties: {
- fileId: {
- type: 'string',
- },
- customCoordinates: {
- type: 'string',
- description:
- 'Define an important area in the image in the format `x,y,width,height` e.g. `10,10,100,100`. Send `null` to unset this value.\n',
- },
- customMetadata: {
- type: 'object',
- description:
- 'A key-value data to be associated with the asset. To unset a key, send `null` value for that key. Before setting any custom metadata on an asset you have to create the field using custom metadata fields API.\n',
- additionalProperties: true,
- },
- description: {
- type: 'string',
- description: 'Optional text to describe the contents of the file.\n',
- },
- extensions: {
- $ref: '#/$defs/extensions',
- },
- removeAITags: {
- anyOf: [
- {
- type: 'array',
- items: {
- type: 'string',
- },
- },
- {
- type: 'string',
- enum: ['all'],
- },
- ],
- description:
- 'An array of AITags associated with the file that you want to remove, e.g. `["car", "vehicle", "motorsports"]`. \n\nIf you want to remove all AITags associated with the file, send a string - "all".\n\nNote: The remove operation for `AITags` executes before any of the `extensions` are processed.\n',
- },
- tags: {
- type: 'array',
- description:
- 'An array of tags associated with the file, such as `["tag1", "tag2"]`. Send `null` to unset all tags associated with the file.\n',
- items: {
- type: 'string',
- },
- },
- webhookUrl: {
- type: 'string',
- description:
- 'The final status of extensions after they have completed execution will be delivered to this endpoint as a POST request. [Learn more](/docs/api-reference/digital-asset-management-dam/managing-assets/update-file-details#webhook-payload-structure) about the webhook payload structure.\n',
- },
- },
- required: ['fileId'],
- },
- {
- type: 'object',
- properties: {
- fileId: {
- type: 'string',
- },
- publish: {
- type: 'object',
- description: 'Configure the publication status of a file and its versions.\n',
- properties: {
- isPublished: {
- type: 'boolean',
- description: 'Set to `true` to publish the file. Set to `false` to unpublish the file.\n',
- },
- includeFileVersions: {
- type: 'boolean',
- description:
- 'Set to `true` to publish/unpublish all versions of the file. Set to `false` to publish/unpublish only the current version of the file.\n',
- },
- },
- required: ['isPublished'],
- },
- },
- required: ['fileId'],
- },
- ],
- $defs: {
- extensions: {
- type: 'array',
- title: 'Extensions Array',
- description:
- 'Array of extensions to be applied to the asset. Each extension can be configured with specific parameters based on the extension type.\n',
- items: {
- anyOf: [
- {
- type: 'object',
- title: 'Remove background',
- properties: {
- name: {
- type: 'string',
- description: 'Specifies the background removal extension.',
- enum: ['remove-bg'],
- },
- options: {
- type: 'object',
- properties: {
- add_shadow: {
- type: 'boolean',
- description:
- 'Whether to add an artificial shadow to the result. Default is false. Note: Adding shadows is currently only supported for car photos.\n',
- },
- bg_color: {
- type: 'string',
- description:
- 'Specifies a solid color background using hex code (e.g., "81d4fa", "fff") or color name (e.g., "green"). If this parameter is set, `bg_image_url` must be empty.\n',
- },
- bg_image_url: {
- type: 'string',
- description:
- 'Sets a background image from a URL. If this parameter is set, `bg_color` must be empty.\n',
- },
- semitransparency: {
- type: 'boolean',
- description:
- 'Allows semi-transparent regions in the result. Default is true. Note: Semitransparency is currently only supported for car windows.\n',
- },
- },
- },
- },
- required: ['name'],
- },
- {
- type: 'object',
- title: 'Auto tagging',
- properties: {
- maxTags: {
- type: 'integer',
- description: 'Maximum number of tags to attach to the asset.',
- },
- minConfidence: {
- type: 'integer',
- description: 'Minimum confidence level for tags to be considered valid.',
- },
- name: {
- type: 'string',
- description: 'Specifies the auto-tagging extension used.',
- enum: ['google-auto-tagging', 'aws-auto-tagging'],
- },
- },
- required: ['maxTags', 'minConfidence', 'name'],
- },
- {
- type: 'object',
- title: 'Auto description',
- properties: {
- name: {
- type: 'string',
- description: 'Specifies the auto description extension.',
- enum: ['ai-auto-description'],
- },
- },
- required: ['name'],
- },
- ],
- },
- },
- },
- },
- annotations: {},
-};
-
-export const handler = async (client: ImageKit, args: Record | undefined) => {
- const { fileId, ...body } = args as any;
- return asTextContentResult(await client.files.update(fileId, body));
-};
-
-export default { metadata, tool, handler };
diff --git a/packages/mcp-server/src/tools/files/upload-files.ts b/packages/mcp-server/src/tools/files/upload-files.ts
deleted file mode 100644
index 60e8fdda..00000000
--- a/packages/mcp-server/src/tools/files/upload-files.ts
+++ /dev/null
@@ -1,332 +0,0 @@
-// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
-
-import { Metadata, asTextContentResult } from '@imagekit/api-mcp/tools/types';
-
-import { Tool } from '@modelcontextprotocol/sdk/types.js';
-import ImageKit from '@imagekit/nodejs';
-
-export const metadata: Metadata = {
- resource: 'files',
- operation: 'write',
- tags: [],
- httpMethod: 'post',
- httpPath: '/api/v1/files/upload',
- operationId: 'upload-file',
-};
-
-export const tool: Tool = {
- name: 'upload_files',
- description:
- 'ImageKit.io allows you to upload files directly from both the server and client sides. For server-side uploads, private API key authentication is used. For client-side uploads, generate a one-time `token`, `signature`, and `expire` from your secure backend using private API. [Learn more](/docs/api-reference/upload-file/upload-file#how-to-implement-client-side-file-upload) about how to implement client-side file upload.\n\nThe [V2 API](/docs/api-reference/upload-file/upload-file-v2) enhances security by verifying the entire payload using JWT.\n\n**File size limit** \\\nOn the free plan, the maximum upload file sizes are 20MB for images, audio, and raw files and 100MB for videos. On the paid plan, these limits increase to 40MB for images, audio, and raw files and 2GB for videos. These limits can be further increased with higher-tier plans.\n\n**Version limit** \\\nA file can have a maximum of 100 versions.\n\n**Demo applications**\n\n- A full-fledged [upload widget using Uppy](https://github.com/imagekit-samples/uppy-uploader), supporting file selections from local storage, URL, Dropbox, Google Drive, Instagram, and more.\n- [Quick start guides](/docs/quick-start-guides) for various frameworks and technologies.\n',
- inputSchema: {
- type: 'object',
- properties: {
- file: {
- type: 'string',
- description:
- 'The API accepts any of the following:\n\n- **Binary data** – send the raw bytes as `multipart/form-data`.\n- **HTTP / HTTPS URL** – a publicly reachable URL that ImageKit’s servers can fetch.\n- **Base64 string** – the file encoded as a Base64 data URI or plain Base64.\n\nWhen supplying a URL, the server must receive the response headers within 8 seconds; otherwise the request fails with 400 Bad Request.\n',
- },
- fileName: {
- type: 'string',
- description:
- 'The name with which the file has to be uploaded.\nThe file name can contain:\n\n - Alphanumeric Characters: `a-z`, `A-Z`, `0-9`.\n - Special Characters: `.`, `-`\n\nAny other character including space will be replaced by `_`\n',
- },
- token: {
- type: 'string',
- description:
- 'A unique value that the ImageKit.io server will use to recognize and prevent subsequent retries for the same request. We suggest using V4 UUIDs, or another random string with enough entropy to avoid collisions. This field is only required for authentication when uploading a file from the client side.\n\n**Note**: Sending a value that has been used in the past will result in a validation error. Even if your previous request resulted in an error, you should always send a new value for this field.\n',
- },
- checks: {
- type: 'string',
- description:
- 'Server-side checks to run on the asset.\nRead more about [Upload API checks](/docs/api-reference/upload-file/upload-file#upload-api-checks).\n',
- },
- customCoordinates: {
- type: 'string',
- description:
- 'Define an important area in the image. This is only relevant for image type files.\n\n - To be passed as a string with the x and y coordinates of the top-left corner, and width and height of the area of interest in the format `x,y,width,height`. For example - `10,10,100,100`\n - Can be used with fo-customtransformation.\n - If this field is not specified and the file is overwritten, then customCoordinates will be removed.\n',
- },
- customMetadata: {
- type: 'object',
- description:
- 'JSON key-value pairs to associate with the asset. Create the custom metadata fields before setting these values.\n',
- additionalProperties: true,
- },
- description: {
- type: 'string',
- description: 'Optional text to describe the contents of the file.\n',
- },
- expire: {
- type: 'integer',
- description:
- 'The time until your signature is valid. It must be a [Unix time](https://en.wikipedia.org/wiki/Unix_time) in less than 1 hour into the future. It should be in seconds. This field is only required for authentication when uploading a file from the client side.\n',
- },
- extensions: {
- $ref: '#/$defs/extensions',
- },
- folder: {
- type: 'string',
- description:
- "The folder path in which the image has to be uploaded. If the folder(s) didn't exist before, a new folder(s) is created.\n\nThe folder name can contain:\n\n - Alphanumeric Characters: `a-z` , `A-Z` , `0-9`\n - Special Characters: `/` , `_` , `-`\n\nUsing multiple `/` creates a nested folder.\n",
- },
- isPrivateFile: {
- type: 'boolean',
- description:
- 'Whether to mark the file as private or not.\n\nIf `true`, the file is marked as private and is accessible only using named transformation or signed URL.\n',
- },
- isPublished: {
- type: 'boolean',
- description:
- 'Whether to upload file as published or not.\n\nIf `false`, the file is marked as unpublished, which restricts access to the file only via the media library. Files in draft or unpublished state can only be publicly accessed after being published.\n\nThe option to upload in draft state is only available in custom enterprise pricing plans.\n',
- },
- overwriteAITags: {
- type: 'boolean',
- description:
- 'If set to `true` and a file already exists at the exact location, its AITags will be removed. Set `overwriteAITags` to `false` to preserve AITags.\n',
- },
- overwriteCustomMetadata: {
- type: 'boolean',
- description:
- 'If the request does not have `customMetadata`, and a file already exists at the exact location, existing customMetadata will be removed.\n',
- },
- overwriteFile: {
- type: 'boolean',
- description:
- 'If `false` and `useUniqueFileName` is also `false`, and a file already exists at the exact location, upload API will return an error immediately.\n',
- },
- overwriteTags: {
- type: 'boolean',
- description:
- 'If the request does not have `tags`, and a file already exists at the exact location, existing tags will be removed.\n',
- },
- publicKey: {
- type: 'string',
- description:
- 'Your ImageKit.io public key. This field is only required for authentication when uploading a file from the client side.\n',
- },
- responseFields: {
- type: 'array',
- description: 'Array of response field keys to include in the API response body.\n',
- items: {
- type: 'string',
- enum: [
- 'tags',
- 'customCoordinates',
- 'isPrivateFile',
- 'embeddedMetadata',
- 'isPublished',
- 'customMetadata',
- 'metadata',
- 'selectedFieldsSchema',
- ],
- },
- },
- signature: {
- type: 'string',
- description:
- 'HMAC-SHA1 digest of the token+expire using your ImageKit.io private API key as a key. Learn how to create a signature on the page below. This should be in lowercase.\n\nSignature must be calculated on the server-side. This field is only required for authentication when uploading a file from the client side.\n',
- },
- tags: {
- type: 'array',
- description:
- 'Set the tags while uploading the file.\nProvide an array of tag strings (e.g. `["tag1", "tag2", "tag3"]`). The combined length of all tag characters must not exceed 500, and the `%` character is not allowed.\nIf this field is not specified and the file is overwritten, the existing tags will be removed.\n',
- items: {
- type: 'string',
- },
- },
- transformation: {
- type: 'object',
- description:
- "Configure pre-processing (`pre`) and post-processing (`post`) transformations.\n\n- `pre` — applied before the file is uploaded to the Media Library. \n Useful for reducing file size or applying basic optimizations upfront (e.g., resize, compress).\n\n- `post` — applied immediately after upload. \n Ideal for generating transformed versions (like video encodes or thumbnails) in advance, so they're ready for delivery without delay.\n\nYou can mix and match any combination of post-processing types.\n",
- properties: {
- post: {
- type: 'array',
- description:
- 'List of transformations to apply *after* the file is uploaded. \nEach item must match one of the following types:\n`transformation`, `gif-to-video`, `thumbnail`, `abs`.\n',
- items: {
- anyOf: [
- {
- type: 'object',
- title: 'Simple post-transformation',
- properties: {
- type: {
- type: 'string',
- description: 'Transformation type.',
- enum: ['transformation'],
- },
- value: {
- type: 'string',
- description:
- 'Transformation string (e.g. `w-200,h-200`). \nSame syntax as ImageKit URL-based transformations.\n',
- },
- },
- required: ['type', 'value'],
- },
- {
- type: 'object',
- title: 'Convert GIF to video',
- properties: {
- type: {
- type: 'string',
- description: 'Converts an animated GIF into an MP4.',
- enum: ['gif-to-video'],
- },
- value: {
- type: 'string',
- description:
- 'Optional transformation string to apply to the output video. \n**Example**: `q-80`\n',
- },
- },
- required: ['type'],
- },
- {
- type: 'object',
- title: 'Generate a thumbnail',
- properties: {
- type: {
- type: 'string',
- description: 'Generates a thumbnail image.',
- enum: ['thumbnail'],
- },
- value: {
- type: 'string',
- description: 'Optional transformation string. \n**Example**: `w-150,h-150`\n',
- },
- },
- required: ['type'],
- },
- {
- type: 'object',
- title: 'Adaptive Bitrate Streaming',
- properties: {
- protocol: {
- type: 'string',
- description: 'Streaming protocol to use (`hls` or `dash`).',
- enum: ['hls', 'dash'],
- },
- type: {
- type: 'string',
- description: 'Adaptive Bitrate Streaming (ABS) setup.',
- enum: ['abs'],
- },
- value: {
- type: 'string',
- description:
- 'List of different representations you want to create separated by an underscore.\n',
- },
- },
- required: ['protocol', 'type', 'value'],
- },
- ],
- },
- },
- pre: {
- type: 'string',
- description:
- 'Transformation string to apply before uploading the file to the Media Library. Useful for optimizing files at ingestion.\n',
- },
- },
- },
- useUniqueFileName: {
- type: 'boolean',
- description:
- 'Whether to use a unique filename for this file or not.\n\nIf `true`, ImageKit.io will add a unique suffix to the filename parameter to get a unique filename.\n\nIf `false`, then the image is uploaded with the provided filename parameter, and any existing file with the same name is replaced.\n',
- },
- webhookUrl: {
- type: 'string',
- description:
- 'The final status of extensions after they have completed execution will be delivered to this endpoint as a POST request. [Learn more](/docs/api-reference/digital-asset-management-dam/managing-assets/update-file-details#webhook-payload-structure) about the webhook payload structure.\n',
- },
- },
- required: ['file', 'fileName'],
- $defs: {
- extensions: {
- type: 'array',
- title: 'Extensions Array',
- description:
- 'Array of extensions to be applied to the asset. Each extension can be configured with specific parameters based on the extension type.\n',
- items: {
- anyOf: [
- {
- type: 'object',
- title: 'Remove background',
- properties: {
- name: {
- type: 'string',
- description: 'Specifies the background removal extension.',
- enum: ['remove-bg'],
- },
- options: {
- type: 'object',
- properties: {
- add_shadow: {
- type: 'boolean',
- description:
- 'Whether to add an artificial shadow to the result. Default is false. Note: Adding shadows is currently only supported for car photos.\n',
- },
- bg_color: {
- type: 'string',
- description:
- 'Specifies a solid color background using hex code (e.g., "81d4fa", "fff") or color name (e.g., "green"). If this parameter is set, `bg_image_url` must be empty.\n',
- },
- bg_image_url: {
- type: 'string',
- description:
- 'Sets a background image from a URL. If this parameter is set, `bg_color` must be empty.\n',
- },
- semitransparency: {
- type: 'boolean',
- description:
- 'Allows semi-transparent regions in the result. Default is true. Note: Semitransparency is currently only supported for car windows.\n',
- },
- },
- },
- },
- required: ['name'],
- },
- {
- type: 'object',
- title: 'Auto tagging',
- properties: {
- maxTags: {
- type: 'integer',
- description: 'Maximum number of tags to attach to the asset.',
- },
- minConfidence: {
- type: 'integer',
- description: 'Minimum confidence level for tags to be considered valid.',
- },
- name: {
- type: 'string',
- description: 'Specifies the auto-tagging extension used.',
- enum: ['google-auto-tagging', 'aws-auto-tagging'],
- },
- },
- required: ['maxTags', 'minConfidence', 'name'],
- },
- {
- type: 'object',
- title: 'Auto description',
- properties: {
- name: {
- type: 'string',
- description: 'Specifies the auto description extension.',
- enum: ['ai-auto-description'],
- },
- },
- required: ['name'],
- },
- ],
- },
- },
- },
- },
- annotations: {},
-};
-
-export const handler = async (client: ImageKit, args: Record | undefined) => {
- const body = args as any;
- return asTextContentResult(await client.files.upload(body));
-};
-
-export default { metadata, tool, handler };
diff --git a/packages/mcp-server/src/tools/files/versions/delete-files-versions.ts b/packages/mcp-server/src/tools/files/versions/delete-files-versions.ts
deleted file mode 100644
index df4b1b92..00000000
--- a/packages/mcp-server/src/tools/files/versions/delete-files-versions.ts
+++ /dev/null
@@ -1,52 +0,0 @@
-// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
-
-import { maybeFilter } from '@imagekit/api-mcp/filtering';
-import { Metadata, asTextContentResult } from '@imagekit/api-mcp/tools/types';
-
-import { Tool } from '@modelcontextprotocol/sdk/types.js';
-import ImageKit from '@imagekit/nodejs';
-
-export const metadata: Metadata = {
- resource: 'files.versions',
- operation: 'write',
- tags: [],
- httpMethod: 'delete',
- httpPath: '/v1/files/{fileId}/versions/{versionId}',
- operationId: 'delete-file-version',
-};
-
-export const tool: Tool = {
- name: 'delete_files_versions',
- description:
- "When using this tool, always use the `jq_filter` parameter to reduce the response size and improve performance.\n\nOnly omit if you're sure you don't need the data.\n\nThis API deletes a non-current file version permanently. The API returns an empty response.\n\nNote: If you want to delete all versions of a file, use the delete file API.\n\n\n# Response Schema\n```json\n{\n type: 'object',\n properties: {}\n}\n```",
- inputSchema: {
- type: 'object',
- properties: {
- fileId: {
- type: 'string',
- },
- versionId: {
- type: 'string',
- },
- jq_filter: {
- type: 'string',
- title: 'jq Filter',
- description:
- 'A jq filter to apply to the response to include certain fields. Consult the output schema in the tool description to see the fields that are available.\n\nFor example: to include only the `name` field in every object of a results array, you can provide ".results[].name".\n\nFor more information, see the [jq documentation](https://jqlang.org/manual/).',
- },
- },
- required: ['fileId', 'versionId'],
- },
- annotations: {
- idempotentHint: true,
- },
-};
-
-export const handler = async (client: ImageKit, args: Record | undefined) => {
- const { versionId, jq_filter, ...body } = args as any;
- return asTextContentResult(
- await maybeFilter(jq_filter, await client.files.versions.delete(versionId, body)),
- );
-};
-
-export default { metadata, tool, handler };
diff --git a/packages/mcp-server/src/tools/files/versions/get-files-versions.ts b/packages/mcp-server/src/tools/files/versions/get-files-versions.ts
deleted file mode 100644
index bf05d7d1..00000000
--- a/packages/mcp-server/src/tools/files/versions/get-files-versions.ts
+++ /dev/null
@@ -1,50 +0,0 @@
-// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
-
-import { maybeFilter } from '@imagekit/api-mcp/filtering';
-import { Metadata, asTextContentResult } from '@imagekit/api-mcp/tools/types';
-
-import { Tool } from '@modelcontextprotocol/sdk/types.js';
-import ImageKit from '@imagekit/nodejs';
-
-export const metadata: Metadata = {
- resource: 'files.versions',
- operation: 'read',
- tags: [],
- httpMethod: 'get',
- httpPath: '/v1/files/{fileId}/versions/{versionId}',
- operationId: 'get-file-version-details',
-};
-
-export const tool: Tool = {
- name: 'get_files_versions',
- description:
- "When using this tool, always use the `jq_filter` parameter to reduce the response size and improve performance.\n\nOnly omit if you're sure you don't need the data.\n\nThis API returns an object with details or attributes of a file version.\n\n# Response Schema\n```json\n{\n $ref: '#/$defs/file',\n $defs: {\n file: {\n type: 'object',\n title: 'File & File Version',\n description: 'Object containing details of a file or file version.',\n properties: {\n AITags: {\n type: 'array',\n description: 'An array of tags assigned to the file by auto tagging.\\n',\n items: {\n type: 'object',\n properties: {\n confidence: {\n type: 'number',\n description: 'Confidence score of the tag.'\n },\n name: {\n type: 'string',\n description: 'Name of the tag.'\n },\n source: {\n type: 'string',\n description: 'Source of the tag. Possible values are `google-auto-tagging` and `aws-auto-tagging`.'\n }\n }\n }\n },\n createdAt: {\n type: 'string',\n description: 'Date and time when the file was uploaded. The date and time is in ISO8601 format.\\n',\n format: 'date-time'\n },\n customCoordinates: {\n type: 'string',\n description: 'An string with custom coordinates of the file.\\n'\n },\n customMetadata: {\n type: 'object',\n description: 'An object with custom metadata for the file.\\n',\n additionalProperties: true\n },\n description: {\n type: 'string',\n description: 'Optional text to describe the contents of the file. Can be set by the user or the ai-auto-description extension.\\n'\n },\n fileId: {\n type: 'string',\n description: 'Unique identifier of the asset.'\n },\n filePath: {\n type: 'string',\n description: 'Path of the file. This is the path you would use in the URL to access the file. For example, if the file is at the root of the media library, the path will be `/file.jpg`. If the file is inside a folder named `images`, the path will be `/images/file.jpg`.\\n'\n },\n fileType: {\n type: 'string',\n description: 'Type of the file. Possible values are `image`, `non-image`.\\n'\n },\n hasAlpha: {\n type: 'boolean',\n description: 'Specifies if the image has an alpha channel.\\n'\n },\n height: {\n type: 'number',\n description: 'Height of the file.\\n'\n },\n isPrivateFile: {\n type: 'boolean',\n description: 'Specifies if the file is private or not.\\n'\n },\n isPublished: {\n type: 'boolean',\n description: 'Specifies if the file is published or not.\\n'\n },\n mime: {\n type: 'string',\n description: 'MIME type of the file.\\n'\n },\n name: {\n type: 'string',\n description: 'Name of the asset.'\n },\n selectedFieldsSchema: {\n type: 'object',\n description: 'This field is included in the response only if the Path policy feature is available in the plan.\\nIt contains schema definitions for the custom metadata fields selected for the specified file path.\\nField selection can only be done when the Path policy feature is enabled.\\n\\nKeys are the names of the custom metadata fields; the value object has details about the custom metadata schema.\\n',\n additionalProperties: true\n },\n size: {\n type: 'number',\n description: 'Size of the file in bytes.\\n'\n },\n tags: {\n type: 'array',\n description: 'An array of tags assigned to the file. Tags are used to search files in the media library.\\n',\n items: {\n type: 'string'\n }\n },\n thumbnail: {\n type: 'string',\n description: 'URL of the thumbnail image. This URL is used to access the thumbnail image of the file in the media library.\\n'\n },\n type: {\n type: 'string',\n description: 'Type of the asset.',\n enum: [ 'file',\n 'file-version'\n ]\n },\n updatedAt: {\n type: 'string',\n description: 'Date and time when the file was last updated. The date and time is in ISO8601 format.\\n',\n format: 'date-time'\n },\n url: {\n type: 'string',\n description: 'URL of the file.\\n'\n },\n versionInfo: {\n type: 'object',\n description: 'An object with details of the file version.\\n',\n properties: {\n id: {\n type: 'string',\n description: 'Unique identifier of the file version.'\n },\n name: {\n type: 'string',\n description: 'Name of the file version.'\n }\n }\n },\n width: {\n type: 'number',\n description: 'Width of the file.\\n'\n }\n }\n }\n }\n}\n```",
- inputSchema: {
- type: 'object',
- properties: {
- fileId: {
- type: 'string',
- },
- versionId: {
- type: 'string',
- },
- jq_filter: {
- type: 'string',
- title: 'jq Filter',
- description:
- 'A jq filter to apply to the response to include certain fields. Consult the output schema in the tool description to see the fields that are available.\n\nFor example: to include only the `name` field in every object of a results array, you can provide ".results[].name".\n\nFor more information, see the [jq documentation](https://jqlang.org/manual/).',
- },
- },
- required: ['fileId', 'versionId'],
- },
- annotations: {
- readOnlyHint: true,
- },
-};
-
-export const handler = async (client: ImageKit, args: Record | undefined) => {
- const { versionId, jq_filter, ...body } = args as any;
- return asTextContentResult(await maybeFilter(jq_filter, await client.files.versions.get(versionId, body)));
-};
-
-export default { metadata, tool, handler };
diff --git a/packages/mcp-server/src/tools/files/versions/list-files-versions.ts b/packages/mcp-server/src/tools/files/versions/list-files-versions.ts
deleted file mode 100644
index 7ea542e2..00000000
--- a/packages/mcp-server/src/tools/files/versions/list-files-versions.ts
+++ /dev/null
@@ -1,47 +0,0 @@
-// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
-
-import { maybeFilter } from '@imagekit/api-mcp/filtering';
-import { Metadata, asTextContentResult } from '@imagekit/api-mcp/tools/types';
-
-import { Tool } from '@modelcontextprotocol/sdk/types.js';
-import ImageKit from '@imagekit/nodejs';
-
-export const metadata: Metadata = {
- resource: 'files.versions',
- operation: 'read',
- tags: [],
- httpMethod: 'get',
- httpPath: '/v1/files/{fileId}/versions',
- operationId: 'list-file-versions',
-};
-
-export const tool: Tool = {
- name: 'list_files_versions',
- description:
- "When using this tool, always use the `jq_filter` parameter to reduce the response size and improve performance.\n\nOnly omit if you're sure you don't need the data.\n\nThis API returns details of all versions of a file.\n\n\n# Response Schema\n```json\n{\n type: 'array',\n items: {\n $ref: '#/$defs/file'\n },\n $defs: {\n file: {\n type: 'object',\n title: 'File & File Version',\n description: 'Object containing details of a file or file version.',\n properties: {\n AITags: {\n type: 'array',\n description: 'An array of tags assigned to the file by auto tagging.\\n',\n items: {\n type: 'object',\n properties: {\n confidence: {\n type: 'number',\n description: 'Confidence score of the tag.'\n },\n name: {\n type: 'string',\n description: 'Name of the tag.'\n },\n source: {\n type: 'string',\n description: 'Source of the tag. Possible values are `google-auto-tagging` and `aws-auto-tagging`.'\n }\n }\n }\n },\n createdAt: {\n type: 'string',\n description: 'Date and time when the file was uploaded. The date and time is in ISO8601 format.\\n',\n format: 'date-time'\n },\n customCoordinates: {\n type: 'string',\n description: 'An string with custom coordinates of the file.\\n'\n },\n customMetadata: {\n type: 'object',\n description: 'An object with custom metadata for the file.\\n',\n additionalProperties: true\n },\n description: {\n type: 'string',\n description: 'Optional text to describe the contents of the file. Can be set by the user or the ai-auto-description extension.\\n'\n },\n fileId: {\n type: 'string',\n description: 'Unique identifier of the asset.'\n },\n filePath: {\n type: 'string',\n description: 'Path of the file. This is the path you would use in the URL to access the file. For example, if the file is at the root of the media library, the path will be `/file.jpg`. If the file is inside a folder named `images`, the path will be `/images/file.jpg`.\\n'\n },\n fileType: {\n type: 'string',\n description: 'Type of the file. Possible values are `image`, `non-image`.\\n'\n },\n hasAlpha: {\n type: 'boolean',\n description: 'Specifies if the image has an alpha channel.\\n'\n },\n height: {\n type: 'number',\n description: 'Height of the file.\\n'\n },\n isPrivateFile: {\n type: 'boolean',\n description: 'Specifies if the file is private or not.\\n'\n },\n isPublished: {\n type: 'boolean',\n description: 'Specifies if the file is published or not.\\n'\n },\n mime: {\n type: 'string',\n description: 'MIME type of the file.\\n'\n },\n name: {\n type: 'string',\n description: 'Name of the asset.'\n },\n selectedFieldsSchema: {\n type: 'object',\n description: 'This field is included in the response only if the Path policy feature is available in the plan.\\nIt contains schema definitions for the custom metadata fields selected for the specified file path.\\nField selection can only be done when the Path policy feature is enabled.\\n\\nKeys are the names of the custom metadata fields; the value object has details about the custom metadata schema.\\n',\n additionalProperties: true\n },\n size: {\n type: 'number',\n description: 'Size of the file in bytes.\\n'\n },\n tags: {\n type: 'array',\n description: 'An array of tags assigned to the file. Tags are used to search files in the media library.\\n',\n items: {\n type: 'string'\n }\n },\n thumbnail: {\n type: 'string',\n description: 'URL of the thumbnail image. This URL is used to access the thumbnail image of the file in the media library.\\n'\n },\n type: {\n type: 'string',\n description: 'Type of the asset.',\n enum: [ 'file',\n 'file-version'\n ]\n },\n updatedAt: {\n type: 'string',\n description: 'Date and time when the file was last updated. The date and time is in ISO8601 format.\\n',\n format: 'date-time'\n },\n url: {\n type: 'string',\n description: 'URL of the file.\\n'\n },\n versionInfo: {\n type: 'object',\n description: 'An object with details of the file version.\\n',\n properties: {\n id: {\n type: 'string',\n description: 'Unique identifier of the file version.'\n },\n name: {\n type: 'string',\n description: 'Name of the file version.'\n }\n }\n },\n width: {\n type: 'number',\n description: 'Width of the file.\\n'\n }\n }\n }\n }\n}\n```",
- inputSchema: {
- type: 'object',
- properties: {
- fileId: {
- type: 'string',
- },
- jq_filter: {
- type: 'string',
- title: 'jq Filter',
- description:
- 'A jq filter to apply to the response to include certain fields. Consult the output schema in the tool description to see the fields that are available.\n\nFor example: to include only the `name` field in every object of a results array, you can provide ".results[].name".\n\nFor more information, see the [jq documentation](https://jqlang.org/manual/).',
- },
- },
- required: ['fileId'],
- },
- annotations: {
- readOnlyHint: true,
- },
-};
-
-export const handler = async (client: ImageKit, args: Record | undefined) => {
- const { fileId, jq_filter, ...body } = args as any;
- return asTextContentResult(await maybeFilter(jq_filter, await client.files.versions.list(fileId)));
-};
-
-export default { metadata, tool, handler };
diff --git a/packages/mcp-server/src/tools/files/versions/restore-files-versions.ts b/packages/mcp-server/src/tools/files/versions/restore-files-versions.ts
deleted file mode 100644
index fd9a04bf..00000000
--- a/packages/mcp-server/src/tools/files/versions/restore-files-versions.ts
+++ /dev/null
@@ -1,52 +0,0 @@
-// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
-
-import { maybeFilter } from '@imagekit/api-mcp/filtering';
-import { Metadata, asTextContentResult } from '@imagekit/api-mcp/tools/types';
-
-import { Tool } from '@modelcontextprotocol/sdk/types.js';
-import ImageKit from '@imagekit/nodejs';
-
-export const metadata: Metadata = {
- resource: 'files.versions',
- operation: 'write',
- tags: [],
- httpMethod: 'put',
- httpPath: '/v1/files/{fileId}/versions/{versionId}/restore',
- operationId: 'restore-file-version',
-};
-
-export const tool: Tool = {
- name: 'restore_files_versions',
- description:
- "When using this tool, always use the `jq_filter` parameter to reduce the response size and improve performance.\n\nOnly omit if you're sure you don't need the data.\n\nThis API restores a file version as the current file version.\n\n\n# Response Schema\n```json\n{\n $ref: '#/$defs/file',\n $defs: {\n file: {\n type: 'object',\n title: 'File & File Version',\n description: 'Object containing details of a file or file version.',\n properties: {\n AITags: {\n type: 'array',\n description: 'An array of tags assigned to the file by auto tagging.\\n',\n items: {\n type: 'object',\n properties: {\n confidence: {\n type: 'number',\n description: 'Confidence score of the tag.'\n },\n name: {\n type: 'string',\n description: 'Name of the tag.'\n },\n source: {\n type: 'string',\n description: 'Source of the tag. Possible values are `google-auto-tagging` and `aws-auto-tagging`.'\n }\n }\n }\n },\n createdAt: {\n type: 'string',\n description: 'Date and time when the file was uploaded. The date and time is in ISO8601 format.\\n',\n format: 'date-time'\n },\n customCoordinates: {\n type: 'string',\n description: 'An string with custom coordinates of the file.\\n'\n },\n customMetadata: {\n type: 'object',\n description: 'An object with custom metadata for the file.\\n',\n additionalProperties: true\n },\n description: {\n type: 'string',\n description: 'Optional text to describe the contents of the file. Can be set by the user or the ai-auto-description extension.\\n'\n },\n fileId: {\n type: 'string',\n description: 'Unique identifier of the asset.'\n },\n filePath: {\n type: 'string',\n description: 'Path of the file. This is the path you would use in the URL to access the file. For example, if the file is at the root of the media library, the path will be `/file.jpg`. If the file is inside a folder named `images`, the path will be `/images/file.jpg`.\\n'\n },\n fileType: {\n type: 'string',\n description: 'Type of the file. Possible values are `image`, `non-image`.\\n'\n },\n hasAlpha: {\n type: 'boolean',\n description: 'Specifies if the image has an alpha channel.\\n'\n },\n height: {\n type: 'number',\n description: 'Height of the file.\\n'\n },\n isPrivateFile: {\n type: 'boolean',\n description: 'Specifies if the file is private or not.\\n'\n },\n isPublished: {\n type: 'boolean',\n description: 'Specifies if the file is published or not.\\n'\n },\n mime: {\n type: 'string',\n description: 'MIME type of the file.\\n'\n },\n name: {\n type: 'string',\n description: 'Name of the asset.'\n },\n selectedFieldsSchema: {\n type: 'object',\n description: 'This field is included in the response only if the Path policy feature is available in the plan.\\nIt contains schema definitions for the custom metadata fields selected for the specified file path.\\nField selection can only be done when the Path policy feature is enabled.\\n\\nKeys are the names of the custom metadata fields; the value object has details about the custom metadata schema.\\n',\n additionalProperties: true\n },\n size: {\n type: 'number',\n description: 'Size of the file in bytes.\\n'\n },\n tags: {\n type: 'array',\n description: 'An array of tags assigned to the file. Tags are used to search files in the media library.\\n',\n items: {\n type: 'string'\n }\n },\n thumbnail: {\n type: 'string',\n description: 'URL of the thumbnail image. This URL is used to access the thumbnail image of the file in the media library.\\n'\n },\n type: {\n type: 'string',\n description: 'Type of the asset.',\n enum: [ 'file',\n 'file-version'\n ]\n },\n updatedAt: {\n type: 'string',\n description: 'Date and time when the file was last updated. The date and time is in ISO8601 format.\\n',\n format: 'date-time'\n },\n url: {\n type: 'string',\n description: 'URL of the file.\\n'\n },\n versionInfo: {\n type: 'object',\n description: 'An object with details of the file version.\\n',\n properties: {\n id: {\n type: 'string',\n description: 'Unique identifier of the file version.'\n },\n name: {\n type: 'string',\n description: 'Name of the file version.'\n }\n }\n },\n width: {\n type: 'number',\n description: 'Width of the file.\\n'\n }\n }\n }\n }\n}\n```",
- inputSchema: {
- type: 'object',
- properties: {
- fileId: {
- type: 'string',
- },
- versionId: {
- type: 'string',
- },
- jq_filter: {
- type: 'string',
- title: 'jq Filter',
- description:
- 'A jq filter to apply to the response to include certain fields. Consult the output schema in the tool description to see the fields that are available.\n\nFor example: to include only the `name` field in every object of a results array, you can provide ".results[].name".\n\nFor more information, see the [jq documentation](https://jqlang.org/manual/).',
- },
- },
- required: ['fileId', 'versionId'],
- },
- annotations: {
- idempotentHint: true,
- },
-};
-
-export const handler = async (client: ImageKit, args: Record | undefined) => {
- const { versionId, jq_filter, ...body } = args as any;
- return asTextContentResult(
- await maybeFilter(jq_filter, await client.files.versions.restore(versionId, body)),
- );
-};
-
-export default { metadata, tool, handler };
diff --git a/packages/mcp-server/src/tools/folders/copy-folders.ts b/packages/mcp-server/src/tools/folders/copy-folders.ts
deleted file mode 100644
index b1efd5fe..00000000
--- a/packages/mcp-server/src/tools/folders/copy-folders.ts
+++ /dev/null
@@ -1,55 +0,0 @@
-// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
-
-import { maybeFilter } from '@imagekit/api-mcp/filtering';
-import { Metadata, asTextContentResult } from '@imagekit/api-mcp/tools/types';
-
-import { Tool } from '@modelcontextprotocol/sdk/types.js';
-import ImageKit from '@imagekit/nodejs';
-
-export const metadata: Metadata = {
- resource: 'folders',
- operation: 'write',
- tags: [],
- httpMethod: 'post',
- httpPath: '/v1/bulkJobs/copyFolder',
- operationId: 'copy-folder',
-};
-
-export const tool: Tool = {
- name: 'copy_folders',
- description:
- "When using this tool, always use the `jq_filter` parameter to reduce the response size and improve performance.\n\nOnly omit if you're sure you don't need the data.\n\nThis will copy one folder into another. The selected folder, its nested folders, files, and their versions (in `includeVersions` is set to true) are copied in this operation. Note: If any file at the destination has the same name as the source file, then the source file and its versions will be appended to the destination file version history.\n\n\n# Response Schema\n```json\n{\n type: 'object',\n title: 'Async Bulk Job Response',\n description: 'Job submitted successfully. A `jobId` will be returned.',\n properties: {\n jobId: {\n type: 'string',\n description: 'Unique identifier of the bulk job. This can be used to check the status of the bulk job.\\n'\n }\n },\n required: [ 'jobId'\n ]\n}\n```",
- inputSchema: {
- type: 'object',
- properties: {
- destinationPath: {
- type: 'string',
- description: 'Full path to the destination folder where you want to copy the source folder into.\n',
- },
- sourceFolderPath: {
- type: 'string',
- description: 'The full path to the source folder you want to copy.\n',
- },
- includeVersions: {
- type: 'boolean',
- description:
- 'Option to copy all versions of files that are nested inside the selected folder. By default, only the current version of each file will be copied. When set to true, all versions of each file will be copied. Default value - `false`.\n',
- },
- jq_filter: {
- type: 'string',
- title: 'jq Filter',
- description:
- 'A jq filter to apply to the response to include certain fields. Consult the output schema in the tool description to see the fields that are available.\n\nFor example: to include only the `name` field in every object of a results array, you can provide ".results[].name".\n\nFor more information, see the [jq documentation](https://jqlang.org/manual/).',
- },
- },
- required: ['destinationPath', 'sourceFolderPath'],
- },
- annotations: {},
-};
-
-export const handler = async (client: ImageKit, args: Record | undefined) => {
- const { jq_filter, ...body } = args as any;
- return asTextContentResult(await maybeFilter(jq_filter, await client.folders.copy(body)));
-};
-
-export default { metadata, tool, handler };
diff --git a/packages/mcp-server/src/tools/folders/create-folders.ts b/packages/mcp-server/src/tools/folders/create-folders.ts
deleted file mode 100644
index 365f3b02..00000000
--- a/packages/mcp-server/src/tools/folders/create-folders.ts
+++ /dev/null
@@ -1,52 +0,0 @@
-// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
-
-import { maybeFilter } from '@imagekit/api-mcp/filtering';
-import { Metadata, asTextContentResult } from '@imagekit/api-mcp/tools/types';
-
-import { Tool } from '@modelcontextprotocol/sdk/types.js';
-import ImageKit from '@imagekit/nodejs';
-
-export const metadata: Metadata = {
- resource: 'folders',
- operation: 'write',
- tags: [],
- httpMethod: 'post',
- httpPath: '/v1/folder',
- operationId: 'create-folder',
-};
-
-export const tool: Tool = {
- name: 'create_folders',
- description:
- "When using this tool, always use the `jq_filter` parameter to reduce the response size and improve performance.\n\nOnly omit if you're sure you don't need the data.\n\nThis will create a new folder. You can specify the folder name and location of the parent folder where this new folder should be created.\n\n\n# Response Schema\n```json\n{\n type: 'object',\n properties: {}\n}\n```",
- inputSchema: {
- type: 'object',
- properties: {
- folderName: {
- type: 'string',
- description:
- 'The folder will be created with this name. \n\nAll characters except alphabets and numbers (inclusive of unicode letters, marks, and numerals in other languages) will be replaced by an underscore i.e. `_`.\n',
- },
- parentFolderPath: {
- type: 'string',
- description:
- "The folder where the new folder should be created, for root use `/` else the path e.g. `containing/folder/`.\n\nNote: If any folder(s) is not present in the parentFolderPath parameter, it will be automatically created. For example, if you pass `/product/images/summer`, then `product`, `images`, and `summer` folders will be created if they don't already exist.\n",
- },
- jq_filter: {
- type: 'string',
- title: 'jq Filter',
- description:
- 'A jq filter to apply to the response to include certain fields. Consult the output schema in the tool description to see the fields that are available.\n\nFor example: to include only the `name` field in every object of a results array, you can provide ".results[].name".\n\nFor more information, see the [jq documentation](https://jqlang.org/manual/).',
- },
- },
- required: ['folderName', 'parentFolderPath'],
- },
- annotations: {},
-};
-
-export const handler = async (client: ImageKit, args: Record | undefined) => {
- const { jq_filter, ...body } = args as any;
- return asTextContentResult(await maybeFilter(jq_filter, await client.folders.create(body)));
-};
-
-export default { metadata, tool, handler };
diff --git a/packages/mcp-server/src/tools/folders/delete-folders.ts b/packages/mcp-server/src/tools/folders/delete-folders.ts
deleted file mode 100644
index b58d0819..00000000
--- a/packages/mcp-server/src/tools/folders/delete-folders.ts
+++ /dev/null
@@ -1,48 +0,0 @@
-// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
-
-import { maybeFilter } from '@imagekit/api-mcp/filtering';
-import { Metadata, asTextContentResult } from '@imagekit/api-mcp/tools/types';
-
-import { Tool } from '@modelcontextprotocol/sdk/types.js';
-import ImageKit from '@imagekit/nodejs';
-
-export const metadata: Metadata = {
- resource: 'folders',
- operation: 'write',
- tags: [],
- httpMethod: 'delete',
- httpPath: '/v1/folder',
- operationId: 'delete-folder',
-};
-
-export const tool: Tool = {
- name: 'delete_folders',
- description:
- "When using this tool, always use the `jq_filter` parameter to reduce the response size and improve performance.\n\nOnly omit if you're sure you don't need the data.\n\nThis will delete a folder and all its contents permanently. The API returns an empty response.\n\n\n# Response Schema\n```json\n{\n type: 'object',\n properties: {}\n}\n```",
- inputSchema: {
- type: 'object',
- properties: {
- folderPath: {
- type: 'string',
- description: 'Full path to the folder you want to delete. For example `/folder/to/delete/`.\n',
- },
- jq_filter: {
- type: 'string',
- title: 'jq Filter',
- description:
- 'A jq filter to apply to the response to include certain fields. Consult the output schema in the tool description to see the fields that are available.\n\nFor example: to include only the `name` field in every object of a results array, you can provide ".results[].name".\n\nFor more information, see the [jq documentation](https://jqlang.org/manual/).',
- },
- },
- required: ['folderPath'],
- },
- annotations: {
- idempotentHint: true,
- },
-};
-
-export const handler = async (client: ImageKit, args: Record | undefined) => {
- const { jq_filter, ...body } = args as any;
- return asTextContentResult(await maybeFilter(jq_filter, await client.folders.delete(body)));
-};
-
-export default { metadata, tool, handler };
diff --git a/packages/mcp-server/src/tools/folders/job/get-folders-job.ts b/packages/mcp-server/src/tools/folders/job/get-folders-job.ts
deleted file mode 100644
index 19ca4ef2..00000000
--- a/packages/mcp-server/src/tools/folders/job/get-folders-job.ts
+++ /dev/null
@@ -1,47 +0,0 @@
-// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
-
-import { maybeFilter } from '@imagekit/api-mcp/filtering';
-import { Metadata, asTextContentResult } from '@imagekit/api-mcp/tools/types';
-
-import { Tool } from '@modelcontextprotocol/sdk/types.js';
-import ImageKit from '@imagekit/nodejs';
-
-export const metadata: Metadata = {
- resource: 'folders.job',
- operation: 'read',
- tags: [],
- httpMethod: 'get',
- httpPath: '/v1/bulkJobs/{jobId}',
- operationId: 'bulk-job-status',
-};
-
-export const tool: Tool = {
- name: 'get_folders_job',
- description:
- "When using this tool, always use the `jq_filter` parameter to reduce the response size and improve performance.\n\nOnly omit if you're sure you don't need the data.\n\nThis API returns the status of a bulk job like copy and move folder operations.\n\n\n# Response Schema\n```json\n{\n type: 'object',\n properties: {\n jobId: {\n type: 'string',\n description: 'Unique identifier of the bulk job.\\n'\n },\n purgeRequestId: {\n type: 'string',\n description: 'Unique identifier of the purge request. This will be present only if `purgeCache` is set to `true` in the rename folder API request.\\n'\n },\n status: {\n type: 'string',\n description: 'Status of the bulk job.',\n enum: [ 'Pending',\n 'Completed'\n ]\n },\n type: {\n type: 'string',\n description: 'Type of the bulk job.',\n enum: [ 'COPY_FOLDER',\n 'MOVE_FOLDER',\n 'RENAME_FOLDER'\n ]\n }\n }\n}\n```",
- inputSchema: {
- type: 'object',
- properties: {
- jobId: {
- type: 'string',
- },
- jq_filter: {
- type: 'string',
- title: 'jq Filter',
- description:
- 'A jq filter to apply to the response to include certain fields. Consult the output schema in the tool description to see the fields that are available.\n\nFor example: to include only the `name` field in every object of a results array, you can provide ".results[].name".\n\nFor more information, see the [jq documentation](https://jqlang.org/manual/).',
- },
- },
- required: ['jobId'],
- },
- annotations: {
- readOnlyHint: true,
- },
-};
-
-export const handler = async (client: ImageKit, args: Record | undefined) => {
- const { jobId, jq_filter, ...body } = args as any;
- return asTextContentResult(await maybeFilter(jq_filter, await client.folders.job.get(jobId)));
-};
-
-export default { metadata, tool, handler };
diff --git a/packages/mcp-server/src/tools/folders/move-folders.ts b/packages/mcp-server/src/tools/folders/move-folders.ts
deleted file mode 100644
index 9131e342..00000000
--- a/packages/mcp-server/src/tools/folders/move-folders.ts
+++ /dev/null
@@ -1,50 +0,0 @@
-// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
-
-import { maybeFilter } from '@imagekit/api-mcp/filtering';
-import { Metadata, asTextContentResult } from '@imagekit/api-mcp/tools/types';
-
-import { Tool } from '@modelcontextprotocol/sdk/types.js';
-import ImageKit from '@imagekit/nodejs';
-
-export const metadata: Metadata = {
- resource: 'folders',
- operation: 'write',
- tags: [],
- httpMethod: 'post',
- httpPath: '/v1/bulkJobs/moveFolder',
- operationId: 'move-folder',
-};
-
-export const tool: Tool = {
- name: 'move_folders',
- description:
- "When using this tool, always use the `jq_filter` parameter to reduce the response size and improve performance.\n\nOnly omit if you're sure you don't need the data.\n\nThis will move one folder into another. The selected folder, its nested folders, files, and their versions are moved in this operation. Note: If any file at the destination has the same name as the source file, then the source file and its versions will be appended to the destination file version history.\n\n\n# Response Schema\n```json\n{\n type: 'object',\n title: 'Async Bulk Job Response',\n description: 'Job submitted successfully. A `jobId` will be returned.',\n properties: {\n jobId: {\n type: 'string',\n description: 'Unique identifier of the bulk job. This can be used to check the status of the bulk job.\\n'\n }\n },\n required: [ 'jobId'\n ]\n}\n```",
- inputSchema: {
- type: 'object',
- properties: {
- destinationPath: {
- type: 'string',
- description: 'Full path to the destination folder where you want to move the source folder into.\n',
- },
- sourceFolderPath: {
- type: 'string',
- description: 'The full path to the source folder you want to move.\n',
- },
- jq_filter: {
- type: 'string',
- title: 'jq Filter',
- description:
- 'A jq filter to apply to the response to include certain fields. Consult the output schema in the tool description to see the fields that are available.\n\nFor example: to include only the `name` field in every object of a results array, you can provide ".results[].name".\n\nFor more information, see the [jq documentation](https://jqlang.org/manual/).',
- },
- },
- required: ['destinationPath', 'sourceFolderPath'],
- },
- annotations: {},
-};
-
-export const handler = async (client: ImageKit, args: Record | undefined) => {
- const { jq_filter, ...body } = args as any;
- return asTextContentResult(await maybeFilter(jq_filter, await client.folders.move(body)));
-};
-
-export default { metadata, tool, handler };
diff --git a/packages/mcp-server/src/tools/folders/rename-folders.ts b/packages/mcp-server/src/tools/folders/rename-folders.ts
deleted file mode 100644
index 83c54224..00000000
--- a/packages/mcp-server/src/tools/folders/rename-folders.ts
+++ /dev/null
@@ -1,56 +0,0 @@
-// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
-
-import { maybeFilter } from '@imagekit/api-mcp/filtering';
-import { Metadata, asTextContentResult } from '@imagekit/api-mcp/tools/types';
-
-import { Tool } from '@modelcontextprotocol/sdk/types.js';
-import ImageKit from '@imagekit/nodejs';
-
-export const metadata: Metadata = {
- resource: 'folders',
- operation: 'write',
- tags: [],
- httpMethod: 'post',
- httpPath: '/v1/bulkJobs/renameFolder',
- operationId: 'rename-folder',
-};
-
-export const tool: Tool = {
- name: 'rename_folders',
- description:
- "When using this tool, always use the `jq_filter` parameter to reduce the response size and improve performance.\n\nOnly omit if you're sure you don't need the data.\n\nThis API allows you to rename an existing folder. The folder and all its nested assets and sub-folders will remain unchanged, but their paths will be updated to reflect the new folder name.\n\n\n# Response Schema\n```json\n{\n type: 'object',\n title: 'Async Bulk Job Response',\n description: 'Job submitted successfully. A `jobId` will be returned.',\n properties: {\n jobId: {\n type: 'string',\n description: 'Unique identifier of the bulk job. This can be used to check the status of the bulk job.\\n'\n }\n },\n required: [ 'jobId'\n ]\n}\n```",
- inputSchema: {
- type: 'object',
- properties: {
- folderPath: {
- type: 'string',
- description: 'The full path to the folder you want to rename.\n',
- },
- newFolderName: {
- type: 'string',
- description:
- 'The new name for the folder.\n\nAll characters except alphabets and numbers (inclusive of unicode letters, marks, and numerals in other languages) and `-` will be replaced by an underscore i.e. `_`.\n',
- },
- purgeCache: {
- type: 'boolean',
- description:
- "Option to purge cache for the old nested files and their versions' URLs.\n\nWhen set to true, it will internally issue a purge cache request on CDN to remove the cached content of the old nested files and their versions. There will only be one purge request for all the nested files, which will be counted against your monthly purge quota.\n\nNote: A purge cache request will be issued against `https://ik.imagekit.io/old/folder/path*` (with a wildcard at the end). This will remove all nested files, their versions' URLs, and any transformations made using query parameters on these files or their versions. However, the cache for file transformations made using path parameters will persist. You can purge them using the purge API. For more details, refer to the purge API documentation.\n\nDefault value - `false`\n",
- },
- jq_filter: {
- type: 'string',
- title: 'jq Filter',
- description:
- 'A jq filter to apply to the response to include certain fields. Consult the output schema in the tool description to see the fields that are available.\n\nFor example: to include only the `name` field in every object of a results array, you can provide ".results[].name".\n\nFor more information, see the [jq documentation](https://jqlang.org/manual/).',
- },
- },
- required: ['folderPath', 'newFolderName'],
- },
- annotations: {},
-};
-
-export const handler = async (client: ImageKit, args: Record | undefined) => {
- const { jq_filter, ...body } = args as any;
- return asTextContentResult(await maybeFilter(jq_filter, await client.folders.rename(body)));
-};
-
-export default { metadata, tool, handler };
diff --git a/packages/mcp-server/src/tools/index.ts b/packages/mcp-server/src/tools/index.ts
deleted file mode 100644
index ba7083d7..00000000
--- a/packages/mcp-server/src/tools/index.ts
+++ /dev/null
@@ -1,153 +0,0 @@
-// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
-
-import { Metadata, Endpoint, HandlerFunction } from './types';
-
-export { Metadata, Endpoint, HandlerFunction };
-
-import create_custom_metadata_fields from './custom-metadata-fields/create-custom-metadata-fields';
-import update_custom_metadata_fields from './custom-metadata-fields/update-custom-metadata-fields';
-import list_custom_metadata_fields from './custom-metadata-fields/list-custom-metadata-fields';
-import delete_custom_metadata_fields from './custom-metadata-fields/delete-custom-metadata-fields';
-import update_files from './files/update-files';
-import delete_files from './files/delete-files';
-import copy_files from './files/copy-files';
-import get_files from './files/get-files';
-import move_files from './files/move-files';
-import rename_files from './files/rename-files';
-import upload_files from './files/upload-files';
-import delete_files_bulk from './files/bulk/delete-files-bulk';
-import add_tags_files_bulk from './files/bulk/add-tags-files-bulk';
-import remove_ai_tags_files_bulk from './files/bulk/remove-ai-tags-files-bulk';
-import remove_tags_files_bulk from './files/bulk/remove-tags-files-bulk';
-import list_files_versions from './files/versions/list-files-versions';
-import delete_files_versions from './files/versions/delete-files-versions';
-import get_files_versions from './files/versions/get-files-versions';
-import restore_files_versions from './files/versions/restore-files-versions';
-import get_files_metadata from './files/metadata/get-files-metadata';
-import get_from_url_files_metadata from './files/metadata/get-from-url-files-metadata';
-import list_assets from './assets/list-assets';
-import create_cache_invalidation from './cache/invalidation/create-cache-invalidation';
-import get_cache_invalidation from './cache/invalidation/get-cache-invalidation';
-import create_folders from './folders/create-folders';
-import delete_folders from './folders/delete-folders';
-import copy_folders from './folders/copy-folders';
-import move_folders from './folders/move-folders';
-import rename_folders from './folders/rename-folders';
-import get_folders_job from './folders/job/get-folders-job';
-import get_accounts_usage from './accounts/usage/get-accounts-usage';
-import create_accounts_origins from './accounts/origins/create-accounts-origins';
-import update_accounts_origins from './accounts/origins/update-accounts-origins';
-import list_accounts_origins from './accounts/origins/list-accounts-origins';
-import delete_accounts_origins from './accounts/origins/delete-accounts-origins';
-import get_accounts_origins from './accounts/origins/get-accounts-origins';
-import create_accounts_url_endpoints from './accounts/url-endpoints/create-accounts-url-endpoints';
-import update_accounts_url_endpoints from './accounts/url-endpoints/update-accounts-url-endpoints';
-import list_accounts_url_endpoints from './accounts/url-endpoints/list-accounts-url-endpoints';
-import delete_accounts_url_endpoints from './accounts/url-endpoints/delete-accounts-url-endpoints';
-import get_accounts_url_endpoints from './accounts/url-endpoints/get-accounts-url-endpoints';
-import upload_v2_beta_files from './beta/v2/files/upload-v2-beta-files';
-
-export const endpoints: Endpoint[] = [];
-
-function addEndpoint(endpoint: Endpoint) {
- endpoints.push(endpoint);
-}
-
-addEndpoint(create_custom_metadata_fields);
-addEndpoint(update_custom_metadata_fields);
-addEndpoint(list_custom_metadata_fields);
-addEndpoint(delete_custom_metadata_fields);
-addEndpoint(update_files);
-addEndpoint(delete_files);
-addEndpoint(copy_files);
-addEndpoint(get_files);
-addEndpoint(move_files);
-addEndpoint(rename_files);
-addEndpoint(upload_files);
-addEndpoint(delete_files_bulk);
-addEndpoint(add_tags_files_bulk);
-addEndpoint(remove_ai_tags_files_bulk);
-addEndpoint(remove_tags_files_bulk);
-addEndpoint(list_files_versions);
-addEndpoint(delete_files_versions);
-addEndpoint(get_files_versions);
-addEndpoint(restore_files_versions);
-addEndpoint(get_files_metadata);
-addEndpoint(get_from_url_files_metadata);
-addEndpoint(list_assets);
-addEndpoint(create_cache_invalidation);
-addEndpoint(get_cache_invalidation);
-addEndpoint(create_folders);
-addEndpoint(delete_folders);
-addEndpoint(copy_folders);
-addEndpoint(move_folders);
-addEndpoint(rename_folders);
-addEndpoint(get_folders_job);
-addEndpoint(get_accounts_usage);
-addEndpoint(create_accounts_origins);
-addEndpoint(update_accounts_origins);
-addEndpoint(list_accounts_origins);
-addEndpoint(delete_accounts_origins);
-addEndpoint(get_accounts_origins);
-addEndpoint(create_accounts_url_endpoints);
-addEndpoint(update_accounts_url_endpoints);
-addEndpoint(list_accounts_url_endpoints);
-addEndpoint(delete_accounts_url_endpoints);
-addEndpoint(get_accounts_url_endpoints);
-addEndpoint(upload_v2_beta_files);
-
-export type Filter = {
- type: 'resource' | 'operation' | 'tag' | 'tool';
- op: 'include' | 'exclude';
- value: string;
-};
-
-export function query(filters: Filter[], endpoints: Endpoint[]): Endpoint[] {
- const allExcludes = filters.length > 0 && filters.every((filter) => filter.op === 'exclude');
- const unmatchedFilters = new Set(filters);
-
- const filtered = endpoints.filter((endpoint: Endpoint) => {
- let included = false || allExcludes;
-
- for (const filter of filters) {
- if (match(filter, endpoint)) {
- unmatchedFilters.delete(filter);
- included = filter.op === 'include';
- }
- }
-
- return included;
- });
-
- // Check if any filters didn't match
- const unmatched = Array.from(unmatchedFilters).filter((f) => f.type === 'tool' || f.type === 'resource');
- if (unmatched.length > 0) {
- throw new Error(
- `The following filters did not match any endpoints: ${unmatched
- .map((f) => `${f.type}=${f.value}`)
- .join(', ')}`,
- );
- }
-
- return filtered;
-}
-
-function match({ type, value }: Filter, endpoint: Endpoint): boolean {
- switch (type) {
- case 'resource': {
- const regexStr = '^' + normalizeResource(value).replace(/\*/g, '.*') + '$';
- const regex = new RegExp(regexStr);
- return regex.test(normalizeResource(endpoint.metadata.resource));
- }
- case 'operation':
- return endpoint.metadata.operation === value;
- case 'tag':
- return endpoint.metadata.tags.includes(value);
- case 'tool':
- return endpoint.tool.name === value;
- }
-}
-
-function normalizeResource(resource: string): string {
- return resource.toLowerCase().replace(/[^a-z.*\-_]*/g, '');
-}
diff --git a/packages/mcp-server/src/tools/types.ts b/packages/mcp-server/src/types.ts
similarity index 91%
rename from packages/mcp-server/src/tools/types.ts
rename to packages/mcp-server/src/types.ts
index 8106d499..6b307bec 100644
--- a/packages/mcp-server/src/tools/types.ts
+++ b/packages/mcp-server/src/types.ts
@@ -87,6 +87,18 @@ export async function asBinaryContentResult(response: Response): Promise {
- it('should return original names when maxLength is 0 or negative', () => {
- const names = ['tool1', 'tool2', 'tool3'];
- expect(truncateToolNames(names, 0)).toEqual(new Map());
- expect(truncateToolNames(names, -1)).toEqual(new Map());
- });
-
- it('should return original names when all names are shorter than maxLength', () => {
- const names = ['tool1', 'tool2', 'tool3'];
- expect(truncateToolNames(names, 10)).toEqual(new Map());
- });
-
- it('should truncate names longer than maxLength', () => {
- const names = ['very-long-tool-name', 'another-long-tool-name', 'short'];
- expect(truncateToolNames(names, 10)).toEqual(
- new Map([
- ['very-long-tool-name', 'very-long-'],
- ['another-long-tool-name', 'another-lo'],
- ]),
- );
- });
-
- it('should handle duplicate truncated names by appending numbers', () => {
- const names = ['tool-name-a', 'tool-name-b', 'tool-name-c'];
- expect(truncateToolNames(names, 8)).toEqual(
- new Map([
- ['tool-name-a', 'tool-na1'],
- ['tool-name-b', 'tool-na2'],
- ['tool-name-c', 'tool-na3'],
- ]),
- );
- });
-});
-
-describe('removeTopLevelUnions', () => {
- const createTestTool = (overrides = {}): Tool => ({
- name: 'test-tool',
- description: 'Test tool',
- inputSchema: {
- type: 'object',
- properties: {},
- },
- ...overrides,
- });
-
- it('should return the original tool if it has no anyOf at the top level', () => {
- const tool = createTestTool({
- inputSchema: {
- type: 'object',
- properties: {
- foo: { type: 'string' },
- },
- },
- });
-
- expect(removeTopLevelUnions(tool)).toEqual([tool]);
- });
-
- it('should split a tool with top-level anyOf into multiple tools', () => {
- const tool = createTestTool({
- name: 'union-tool',
- description: 'A tool with unions',
- inputSchema: {
- type: 'object',
- properties: {
- common: { type: 'string' },
- },
- anyOf: [
- {
- title: 'first variant',
- description: 'Its the first variant',
- properties: {
- variant1: { type: 'string' },
- },
- required: ['variant1'],
- },
- {
- title: 'second variant',
- properties: {
- variant2: { type: 'number' },
- },
- required: ['variant2'],
- },
- ],
- },
- });
-
- const result = removeTopLevelUnions(tool);
-
- expect(result).toEqual([
- {
- name: 'union-tool_first_variant',
- description: 'Its the first variant',
- inputSchema: {
- type: 'object',
- title: 'first variant',
- description: 'Its the first variant',
- properties: {
- common: { type: 'string' },
- variant1: { type: 'string' },
- },
- required: ['variant1'],
- },
- },
- {
- name: 'union-tool_second_variant',
- description: 'A tool with unions',
- inputSchema: {
- type: 'object',
- title: 'second variant',
- description: 'A tool with unions',
- properties: {
- common: { type: 'string' },
- variant2: { type: 'number' },
- },
- required: ['variant2'],
- },
- },
- ]);
- });
-
- it('should handle $defs and only include those used by the variant', () => {
- const tool = createTestTool({
- name: 'defs-tool',
- description: 'A tool with $defs',
- inputSchema: {
- type: 'object',
- properties: {
- common: { type: 'string' },
- },
- $defs: {
- def1: { type: 'string', format: 'email' },
- def2: { type: 'number', minimum: 0 },
- unused: { type: 'boolean' },
- },
- anyOf: [
- {
- properties: {
- email: { $ref: '#/$defs/def1' },
- },
- },
- {
- properties: {
- count: { $ref: '#/$defs/def2' },
- },
- },
- ],
- },
- });
-
- const result = removeTopLevelUnions(tool);
-
- expect(result).toEqual([
- {
- name: 'defs-tool_variant1',
- description: 'A tool with $defs',
- inputSchema: {
- type: 'object',
- description: 'A tool with $defs',
- properties: {
- common: { type: 'string' },
- email: { $ref: '#/$defs/def1' },
- },
- $defs: {
- def1: { type: 'string', format: 'email' },
- },
- },
- },
- {
- name: 'defs-tool_variant2',
- description: 'A tool with $defs',
- inputSchema: {
- type: 'object',
- description: 'A tool with $defs',
- properties: {
- common: { type: 'string' },
- count: { $ref: '#/$defs/def2' },
- },
- $defs: {
- def2: { type: 'number', minimum: 0 },
- },
- },
- },
- ]);
- });
-});
-
-describe('removeAnyOf', () => {
- it('should return original schema if it has no anyOf', () => {
- const schema = {
- type: 'object',
- properties: {
- foo: { type: 'string' },
- bar: { type: 'number' },
- },
- };
-
- expect(removeAnyOf(schema)).toEqual(schema);
- });
-
- it('should remove anyOf field and use the first variant', () => {
- const schema = {
- type: 'object',
- properties: {
- common: { type: 'string' },
- },
- anyOf: [
- {
- properties: {
- variant1: { type: 'string' },
- },
- required: ['variant1'],
- },
- {
- properties: {
- variant2: { type: 'number' },
- },
- required: ['variant2'],
- },
- ],
- };
-
- const expected = {
- type: 'object',
- properties: {
- common: { type: 'string' },
- variant1: { type: 'string' },
- },
- required: ['variant1'],
- };
-
- expect(removeAnyOf(schema)).toEqual(expected);
- });
-
- it('should recursively remove anyOf fields from nested properties', () => {
- const schema = {
- type: 'object',
- properties: {
- foo: { type: 'string' },
- nested: {
- type: 'object',
- properties: {
- bar: { type: 'number' },
- },
- anyOf: [
- {
- properties: {
- option1: { type: 'boolean' },
- },
- },
- {
- properties: {
- option2: { type: 'array' },
- },
- },
- ],
- },
- },
- };
-
- const expected = {
- type: 'object',
- properties: {
- foo: { type: 'string' },
- nested: {
- type: 'object',
- properties: {
- bar: { type: 'number' },
- option1: { type: 'boolean' },
- },
- },
- },
- };
-
- expect(removeAnyOf(schema)).toEqual(expected);
- });
-
- it('should handle arrays', () => {
- const schema = {
- type: 'object',
- properties: {
- items: {
- type: 'array',
- items: {
- anyOf: [{ type: 'string' }, { type: 'number' }],
- },
- },
- },
- };
-
- const expected = {
- type: 'object',
- properties: {
- items: {
- type: 'array',
- items: {
- type: 'string',
- },
- },
- },
- };
-
- expect(removeAnyOf(schema)).toEqual(expected);
- });
-});
-
-describe('findUsedDefs', () => {
- it('should handle circular references without stack overflow', () => {
- const defs = {
- person: {
- type: 'object',
- properties: {
- name: { type: 'string' },
- friend: { $ref: '#/$defs/person' }, // Circular reference
- },
- },
- };
-
- const schema = {
- type: 'object',
- properties: {
- user: { $ref: '#/$defs/person' },
- },
- };
-
- // This should not throw a stack overflow error
- expect(() => {
- const result = findUsedDefs(schema, defs);
- expect(result).toHaveProperty('person');
- }).not.toThrow();
- });
-
- it('should handle indirect circular references without stack overflow', () => {
- const defs = {
- node: {
- type: 'object',
- properties: {
- value: { type: 'string' },
- child: { $ref: '#/$defs/childNode' },
- },
- },
- childNode: {
- type: 'object',
- properties: {
- value: { type: 'string' },
- parent: { $ref: '#/$defs/node' }, // Indirect circular reference
- },
- },
- };
-
- const schema = {
- type: 'object',
- properties: {
- root: { $ref: '#/$defs/node' },
- },
- };
-
- // This should not throw a stack overflow error
- expect(() => {
- const result = findUsedDefs(schema, defs);
- expect(result).toHaveProperty('node');
- expect(result).toHaveProperty('childNode');
- }).not.toThrow();
- });
-
- it('should find all used definitions in non-circular schemas', () => {
- const defs = {
- user: {
- type: 'object',
- properties: {
- name: { type: 'string' },
- address: { $ref: '#/$defs/address' },
- },
- },
- address: {
- type: 'object',
- properties: {
- street: { type: 'string' },
- city: { type: 'string' },
- },
- },
- unused: {
- type: 'object',
- properties: {
- data: { type: 'string' },
- },
- },
- };
-
- const schema = {
- type: 'object',
- properties: {
- person: { $ref: '#/$defs/user' },
- },
- };
-
- const result = findUsedDefs(schema, defs);
- expect(result).toHaveProperty('user');
- expect(result).toHaveProperty('address');
- expect(result).not.toHaveProperty('unused');
- });
-});
-
-describe('inlineRefs', () => {
- it('should return the original schema if it does not contain $refs', () => {
- const schema: JSONSchema = {
- type: 'object',
- properties: {
- name: { type: 'string' },
- age: { type: 'number' },
- },
- };
-
- expect(inlineRefs(schema)).toEqual(schema);
- });
-
- it('should inline simple $refs', () => {
- const schema: JSONSchema = {
- type: 'object',
- properties: {
- user: { $ref: '#/$defs/user' },
- },
- $defs: {
- user: {
- type: 'object',
- properties: {
- name: { type: 'string' },
- email: { type: 'string' },
- },
- },
- },
- };
-
- const expected: JSONSchema = {
- type: 'object',
- properties: {
- user: {
- type: 'object',
- properties: {
- name: { type: 'string' },
- email: { type: 'string' },
- },
- },
- },
- };
-
- expect(inlineRefs(schema)).toEqual(expected);
- });
-
- it('should inline nested $refs', () => {
- const schema: JSONSchema = {
- type: 'object',
- properties: {
- order: { $ref: '#/$defs/order' },
- },
- $defs: {
- order: {
- type: 'object',
- properties: {
- id: { type: 'string' },
- items: { type: 'array', items: { $ref: '#/$defs/item' } },
- },
- },
- item: {
- type: 'object',
- properties: {
- product: { type: 'string' },
- quantity: { type: 'integer' },
- },
- },
- },
- };
-
- const expected: JSONSchema = {
- type: 'object',
- properties: {
- order: {
- type: 'object',
- properties: {
- id: { type: 'string' },
- items: {
- type: 'array',
- items: {
- type: 'object',
- properties: {
- product: { type: 'string' },
- quantity: { type: 'integer' },
- },
- },
- },
- },
- },
- },
- };
-
- expect(inlineRefs(schema)).toEqual(expected);
- });
-
- it('should handle circular references by removing the circular part', () => {
- const schema: JSONSchema = {
- type: 'object',
- properties: {
- person: { $ref: '#/$defs/person' },
- },
- $defs: {
- person: {
- type: 'object',
- properties: {
- name: { type: 'string' },
- friend: { $ref: '#/$defs/person' }, // Circular reference
- },
- },
- },
- };
-
- const expected: JSONSchema = {
- type: 'object',
- properties: {
- person: {
- type: 'object',
- properties: {
- name: { type: 'string' },
- // friend property is removed to break the circular reference
- },
- },
- },
- };
-
- expect(inlineRefs(schema)).toEqual(expected);
- });
-
- it('should handle indirect circular references', () => {
- const schema: JSONSchema = {
- type: 'object',
- properties: {
- node: { $ref: '#/$defs/node' },
- },
- $defs: {
- node: {
- type: 'object',
- properties: {
- value: { type: 'string' },
- child: { $ref: '#/$defs/childNode' },
- },
- },
- childNode: {
- type: 'object',
- properties: {
- value: { type: 'string' },
- parent: { $ref: '#/$defs/node' }, // Circular reference through childNode
- },
- },
- },
- };
-
- const expected: JSONSchema = {
- type: 'object',
- properties: {
- node: {
- type: 'object',
- properties: {
- value: { type: 'string' },
- child: {
- type: 'object',
- properties: {
- value: { type: 'string' },
- // parent property is removed to break the circular reference
- },
- },
- },
- },
- },
- };
-
- expect(inlineRefs(schema)).toEqual(expected);
- });
-
- it('should preserve other properties when inlining references', () => {
- const schema: JSONSchema = {
- type: 'object',
- properties: {
- address: { $ref: '#/$defs/address', description: 'User address' },
- },
- $defs: {
- address: {
- type: 'object',
- properties: {
- street: { type: 'string' },
- city: { type: 'string' },
- },
- required: ['street'],
- },
- },
- };
-
- const expected: JSONSchema = {
- type: 'object',
- properties: {
- address: {
- type: 'object',
- description: 'User address',
- properties: {
- street: { type: 'string' },
- city: { type: 'string' },
- },
- required: ['street'],
- },
- },
- };
-
- expect(inlineRefs(schema)).toEqual(expected);
- });
-});
-
-describe('removeFormats', () => {
- it('should return original schema if formats capability is true', () => {
- const schema = {
- type: 'object',
- properties: {
- date: { type: 'string', description: 'A date field', format: 'date' },
- email: { type: 'string', description: 'An email field', format: 'email' },
- },
- };
-
- expect(removeFormats(schema, true)).toEqual(schema);
- });
-
- it('should move format to description when formats capability is false', () => {
- const schema = {
- type: 'object',
- properties: {
- date: { type: 'string', description: 'A date field', format: 'date' },
- email: { type: 'string', description: 'An email field', format: 'email' },
- },
- };
-
- const expected = {
- type: 'object',
- properties: {
- date: { type: 'string', description: 'A date field (format: "date")' },
- email: { type: 'string', description: 'An email field (format: "email")' },
- },
- };
-
- expect(removeFormats(schema, false)).toEqual(expected);
- });
-
- it('should handle properties without description', () => {
- const schema = {
- type: 'object',
- properties: {
- date: { type: 'string', format: 'date' },
- },
- };
-
- const expected = {
- type: 'object',
- properties: {
- date: { type: 'string', description: '(format: "date")' },
- },
- };
-
- expect(removeFormats(schema, false)).toEqual(expected);
- });
-
- it('should handle nested properties', () => {
- const schema = {
- type: 'object',
- properties: {
- user: {
- type: 'object',
- properties: {
- created_at: { type: 'string', description: 'Creation date', format: 'date-time' },
- },
- },
- },
- };
-
- const expected = {
- type: 'object',
- properties: {
- user: {
- type: 'object',
- properties: {
- created_at: { type: 'string', description: 'Creation date (format: "date-time")' },
- },
- },
- },
- };
-
- expect(removeFormats(schema, false)).toEqual(expected);
- });
-
- it('should handle arrays of objects', () => {
- const schema = {
- type: 'object',
- properties: {
- dates: {
- type: 'array',
- items: {
- type: 'object',
- properties: {
- start: { type: 'string', description: 'Start date', format: 'date' },
- end: { type: 'string', description: 'End date', format: 'date' },
- },
- },
- },
- },
- };
-
- const expected = {
- type: 'object',
- properties: {
- dates: {
- type: 'array',
- items: {
- type: 'object',
- properties: {
- start: { type: 'string', description: 'Start date (format: "date")' },
- end: { type: 'string', description: 'End date (format: "date")' },
- },
- },
- },
- },
- };
-
- expect(removeFormats(schema, false)).toEqual(expected);
- });
-
- it('should handle schemas with $defs', () => {
- const schema = {
- type: 'object',
- properties: {
- date: { type: 'string', description: 'A date field', format: 'date' },
- },
- $defs: {
- timestamp: {
- type: 'string',
- description: 'A timestamp field',
- format: 'date-time',
- },
- },
- };
-
- const expected = {
- type: 'object',
- properties: {
- date: { type: 'string', description: 'A date field (format: "date")' },
- },
- $defs: {
- timestamp: {
- type: 'string',
- description: 'A timestamp field (format: "date-time")',
- },
- },
- };
-
- expect(removeFormats(schema, false)).toEqual(expected);
- });
-});
-
-describe('applyCompatibilityTransformations', () => {
- const createTestTool = (name: string, overrides = {}): Tool => ({
- name,
- description: 'Test tool',
- inputSchema: {
- type: 'object',
- properties: {},
- },
- ...overrides,
- });
-
- const createTestEndpoint = (tool: Tool): Endpoint => ({
- tool,
- handler: jest.fn(),
- metadata: {
- resource: 'test',
- operation: 'read' as const,
- tags: [],
- },
- });
-
- it('should not modify endpoints when all capabilities are enabled', () => {
- const tool = createTestTool('test-tool');
- const endpoints = [createTestEndpoint(tool)];
-
- const capabilities = {
- topLevelUnions: true,
- validJson: true,
- refs: true,
- unions: true,
- formats: true,
- toolNameLength: undefined,
- };
-
- const transformed = applyCompatibilityTransformations(endpoints, capabilities);
- expect(transformed).toEqual(endpoints);
- });
-
- it('should split tools with top-level unions when topLevelUnions is disabled', () => {
- const tool = createTestTool('union-tool', {
- inputSchema: {
- type: 'object',
- properties: {
- common: { type: 'string' },
- },
- anyOf: [
- {
- title: 'first variant',
- properties: {
- variant1: { type: 'string' },
- },
- },
- {
- title: 'second variant',
- properties: {
- variant2: { type: 'number' },
- },
- },
- ],
- },
- });
-
- const endpoints = [createTestEndpoint(tool)];
-
- const capabilities = {
- topLevelUnions: false,
- validJson: true,
- refs: true,
- unions: true,
- formats: true,
- toolNameLength: undefined,
- };
-
- const transformed = applyCompatibilityTransformations(endpoints, capabilities);
- expect(transformed.length).toBe(2);
- expect(transformed[0]!.tool.name).toBe('union-tool_first_variant');
- expect(transformed[1]!.tool.name).toBe('union-tool_second_variant');
- });
-
- it('should handle variants without titles in removeTopLevelUnions', () => {
- const tool = createTestTool('union-tool', {
- inputSchema: {
- type: 'object',
- properties: {
- common: { type: 'string' },
- },
- anyOf: [
- {
- properties: {
- variant1: { type: 'string' },
- },
- },
- {
- properties: {
- variant2: { type: 'number' },
- },
- },
- ],
- },
- });
-
- const endpoints = [createTestEndpoint(tool)];
-
- const capabilities = {
- topLevelUnions: false,
- validJson: true,
- refs: true,
- unions: true,
- formats: true,
- toolNameLength: undefined,
- };
-
- const transformed = applyCompatibilityTransformations(endpoints, capabilities);
- expect(transformed.length).toBe(2);
- expect(transformed[0]!.tool.name).toBe('union-tool_variant1');
- expect(transformed[1]!.tool.name).toBe('union-tool_variant2');
- });
-
- it('should truncate tool names when toolNameLength is set', () => {
- const tools = [
- createTestTool('very-long-tool-name-that-exceeds-limit'),
- createTestTool('another-long-tool-name-to-truncate'),
- createTestTool('short-name'),
- ];
-
- const endpoints = tools.map(createTestEndpoint);
-
- const capabilities = {
- topLevelUnions: true,
- validJson: true,
- refs: true,
- unions: true,
- formats: true,
- toolNameLength: 20,
- };
-
- const transformed = applyCompatibilityTransformations(endpoints, capabilities);
- expect(transformed[0]!.tool.name).toBe('very-long-tool-name-');
- expect(transformed[1]!.tool.name).toBe('another-long-tool-na');
- expect(transformed[2]!.tool.name).toBe('short-name');
- });
-
- it('should inline refs when refs capability is disabled', () => {
- const tool = createTestTool('ref-tool', {
- inputSchema: {
- type: 'object',
- properties: {
- user: { $ref: '#/$defs/user' },
- },
- $defs: {
- user: {
- type: 'object',
- properties: {
- name: { type: 'string' },
- email: { type: 'string' },
- },
- },
- },
- },
- });
-
- const endpoints = [createTestEndpoint(tool)];
-
- const capabilities = {
- topLevelUnions: true,
- validJson: true,
- refs: false,
- unions: true,
- formats: true,
- toolNameLength: undefined,
- };
-
- const transformed = applyCompatibilityTransformations(endpoints, capabilities);
- const schema = transformed[0]!.tool.inputSchema as JSONSchema;
- expect(schema.$defs).toBeUndefined();
-
- if (schema.properties) {
- expect(schema.properties['user']).toEqual({
- type: 'object',
- properties: {
- name: { type: 'string' },
- email: { type: 'string' },
- },
- });
- }
- });
-
- it('should preserve external refs when inlining', () => {
- const tool = createTestTool('ref-tool', {
- inputSchema: {
- type: 'object',
- properties: {
- internal: { $ref: '#/$defs/internal' },
- external: { $ref: 'https://example.com/schemas/external.json' },
- },
- $defs: {
- internal: {
- type: 'object',
- properties: {
- name: { type: 'string' },
- },
- },
- },
- },
- });
-
- const endpoints = [createTestEndpoint(tool)];
-
- const capabilities = {
- topLevelUnions: true,
- validJson: true,
- refs: false,
- unions: true,
- formats: true,
- toolNameLength: undefined,
- };
-
- const transformed = applyCompatibilityTransformations(endpoints, capabilities);
- const schema = transformed[0]!.tool.inputSchema as JSONSchema;
-
- if (schema.properties) {
- expect(schema.properties['internal']).toEqual({
- type: 'object',
- properties: {
- name: { type: 'string' },
- },
- });
- expect(schema.properties['external']).toEqual({
- $ref: 'https://example.com/schemas/external.json',
- });
- }
- });
-
- it('should remove anyOf fields when unions capability is disabled', () => {
- const tool = createTestTool('union-tool', {
- inputSchema: {
- type: 'object',
- properties: {
- field: {
- anyOf: [{ type: 'string' }, { type: 'number' }],
- },
- },
- },
- });
-
- const endpoints = [createTestEndpoint(tool)];
-
- const capabilities = {
- topLevelUnions: true,
- validJson: true,
- refs: true,
- unions: false,
- formats: true,
- toolNameLength: undefined,
- };
-
- const transformed = applyCompatibilityTransformations(endpoints, capabilities);
- const schema = transformed[0]!.tool.inputSchema as JSONSchema;
-
- if (schema.properties && schema.properties['field']) {
- const field = schema.properties['field'];
- expect(field.anyOf).toBeUndefined();
- expect(field.type).toBe('string');
- }
- });
-
- it('should correctly combine topLevelUnions and toolNameLength transformations', () => {
- const tool = createTestTool('very-long-union-tool-name', {
- inputSchema: {
- type: 'object',
- properties: {
- common: { type: 'string' },
- },
- anyOf: [
- {
- title: 'first variant',
- properties: {
- variant1: { type: 'string' },
- },
- },
- {
- title: 'second variant',
- properties: {
- variant2: { type: 'number' },
- },
- },
- ],
- },
- });
-
- const endpoints = [createTestEndpoint(tool)];
-
- const capabilities = {
- topLevelUnions: false,
- validJson: true,
- refs: true,
- unions: true,
- formats: true,
- toolNameLength: 20,
- };
-
- const transformed = applyCompatibilityTransformations(endpoints, capabilities);
- expect(transformed.length).toBe(2);
-
- // Both names should be truncated because they exceed 20 characters
- expect(transformed[0]!.tool.name).toBe('very-long-union-too1');
- expect(transformed[1]!.tool.name).toBe('very-long-union-too2');
- });
-
- it('should correctly combine refs and unions transformations', () => {
- const tool = createTestTool('complex-tool', {
- inputSchema: {
- type: 'object',
- properties: {
- user: { $ref: '#/$defs/user' },
- },
- $defs: {
- user: {
- type: 'object',
- properties: {
- preference: {
- anyOf: [{ type: 'string' }, { type: 'number' }],
- },
- },
- },
- },
- },
- });
-
- const endpoints = [createTestEndpoint(tool)];
-
- const capabilities = {
- topLevelUnions: true,
- validJson: true,
- refs: false,
- unions: false,
- formats: true,
- toolNameLength: undefined,
- };
-
- const transformed = applyCompatibilityTransformations(endpoints, capabilities);
- const schema = transformed[0]!.tool.inputSchema as JSONSchema;
-
- // Refs should be inlined
- expect(schema.$defs).toBeUndefined();
-
- // Safely access nested properties
- if (schema.properties && schema.properties['user']) {
- const user = schema.properties['user'];
- // User should be inlined
- expect(user.type).toBe('object');
-
- // AnyOf in the inlined user.preference should be removed
- if (user.properties && user.properties['preference']) {
- const preference = user.properties['preference'];
- expect(preference.anyOf).toBeUndefined();
- expect(preference.type).toBe('string');
- }
- }
- });
-
- it('should handle formats capability being false', () => {
- const tool = createTestTool('format-tool', {
- inputSchema: {
- type: 'object',
- properties: {
- date: { type: 'string', description: 'A date', format: 'date' },
- },
- },
- });
-
- const endpoints = [createTestEndpoint(tool)];
-
- const capabilities = {
- topLevelUnions: true,
- validJson: true,
- refs: true,
- unions: true,
- formats: false,
- toolNameLength: undefined,
- };
-
- const transformed = applyCompatibilityTransformations(endpoints, capabilities);
- const schema = transformed[0]!.tool.inputSchema as JSONSchema;
-
- if (schema.properties && schema.properties['date']) {
- const dateField = schema.properties['date'];
- expect(dateField['format']).toBeUndefined();
- expect(dateField['description']).toBe('A date (format: "date")');
- }
- });
-});
diff --git a/packages/mcp-server/tests/dynamic-tools.test.ts b/packages/mcp-server/tests/dynamic-tools.test.ts
deleted file mode 100644
index 08963af8..00000000
--- a/packages/mcp-server/tests/dynamic-tools.test.ts
+++ /dev/null
@@ -1,185 +0,0 @@
-import { dynamicTools } from '../src/dynamic-tools';
-import { Endpoint } from '../src/tools';
-
-describe('dynamicTools', () => {
- const fakeClient = {} as any;
-
- const endpoints: Endpoint[] = [
- makeEndpoint('test_read_endpoint', 'test_resource', 'read', ['test']),
- makeEndpoint('test_write_endpoint', 'test_resource', 'write', ['test']),
- makeEndpoint('user_endpoint', 'user', 'read', ['user', 'admin']),
- makeEndpoint('admin_endpoint', 'admin', 'write', ['admin']),
- ];
-
- const tools = dynamicTools(endpoints);
-
- const toolsMap = {
- list_api_endpoints: toolOrError('list_api_endpoints'),
- get_api_endpoint_schema: toolOrError('get_api_endpoint_schema'),
- invoke_api_endpoint: toolOrError('invoke_api_endpoint'),
- };
-
- describe('list_api_endpoints', () => {
- it('should return all endpoints when no search query is provided', async () => {
- const content = await toolsMap.list_api_endpoints.handler(fakeClient, {});
- const result = JSON.parse(content.content[0].text);
-
- expect(result.tools).toHaveLength(endpoints.length);
- expect(result.tools.map((t: { name: string }) => t.name)).toContain('test_read_endpoint');
- expect(result.tools.map((t: { name: string }) => t.name)).toContain('test_write_endpoint');
- expect(result.tools.map((t: { name: string }) => t.name)).toContain('user_endpoint');
- expect(result.tools.map((t: { name: string }) => t.name)).toContain('admin_endpoint');
- });
-
- it('should filter endpoints by name', async () => {
- const content = await toolsMap.list_api_endpoints.handler(fakeClient, { search_query: 'user' });
- const result = JSON.parse(content.content[0].text);
-
- expect(result.tools).toHaveLength(1);
- expect(result.tools[0].name).toBe('user_endpoint');
- });
-
- it('should filter endpoints by resource', async () => {
- const content = await toolsMap.list_api_endpoints.handler(fakeClient, { search_query: 'admin' });
- const result = JSON.parse(content.content[0].text);
-
- expect(result.tools.some((t: { resource: string }) => t.resource === 'admin')).toBeTruthy();
- });
-
- it('should filter endpoints by tag', async () => {
- const content = await toolsMap.list_api_endpoints.handler(fakeClient, { search_query: 'admin' });
- const result = JSON.parse(content.content[0].text);
-
- expect(result.tools.some((t: { tags: string[] }) => t.tags.includes('admin'))).toBeTruthy();
- });
-
- it('should be case insensitive in search', async () => {
- const content = await toolsMap.list_api_endpoints.handler(fakeClient, { search_query: 'ADMIN' });
- const result = JSON.parse(content.content[0].text);
-
- expect(result.tools.length).toBe(2);
- result.tools.forEach((tool: { name: string; resource: string; tags: string[] }) => {
- expect(
- tool.name.toLowerCase().includes('admin') ||
- tool.resource.toLowerCase().includes('admin') ||
- tool.tags.some((tag: string) => tag.toLowerCase().includes('admin')),
- ).toBeTruthy();
- });
- });
-
- it('should filter endpoints by description', async () => {
- const content = await toolsMap.list_api_endpoints.handler(fakeClient, {
- search_query: 'Test endpoint for user_endpoint',
- });
- const result = JSON.parse(content.content[0].text);
-
- expect(result.tools).toHaveLength(1);
- expect(result.tools[0].name).toBe('user_endpoint');
- expect(result.tools[0].description).toBe('Test endpoint for user_endpoint');
- });
-
- it('should filter endpoints by partial description match', async () => {
- const content = await toolsMap.list_api_endpoints.handler(fakeClient, {
- search_query: 'endpoint for user',
- });
- const result = JSON.parse(content.content[0].text);
-
- expect(result.tools).toHaveLength(1);
- expect(result.tools[0].name).toBe('user_endpoint');
- });
- });
-
- describe('get_api_endpoint_schema', () => {
- it('should return schema for existing endpoint', async () => {
- const content = await toolsMap.get_api_endpoint_schema.handler(fakeClient, {
- endpoint: 'test_read_endpoint',
- });
- const result = JSON.parse(content.content[0].text);
-
- expect(result).toEqual(endpoints[0]?.tool);
- });
-
- it('should throw error for non-existent endpoint', async () => {
- await expect(
- toolsMap.get_api_endpoint_schema.handler(fakeClient, { endpoint: 'non_existent_endpoint' }),
- ).rejects.toThrow('Endpoint non_existent_endpoint not found');
- });
-
- it('should throw error when no endpoint provided', async () => {
- await expect(toolsMap.get_api_endpoint_schema.handler(fakeClient, undefined)).rejects.toThrow(
- 'No endpoint provided',
- );
- });
- });
-
- describe('invoke_api_endpoint', () => {
- it('should successfully invoke endpoint with valid arguments', async () => {
- const mockHandler = endpoints[0]?.handler as jest.Mock;
- mockHandler.mockClear();
-
- await toolsMap.invoke_api_endpoint.handler(fakeClient, {
- endpoint_name: 'test_read_endpoint',
- args: { testParam: 'test value' },
- });
-
- expect(mockHandler).toHaveBeenCalledWith(fakeClient, { testParam: 'test value' });
- });
-
- it('should throw error for non-existent endpoint', async () => {
- await expect(
- toolsMap.invoke_api_endpoint.handler(fakeClient, {
- endpoint_name: 'non_existent_endpoint',
- args: { testParam: 'test value' },
- }),
- ).rejects.toThrow(/Endpoint non_existent_endpoint not found/);
- });
-
- it('should throw error when no arguments provided', async () => {
- await expect(toolsMap.invoke_api_endpoint.handler(fakeClient, undefined)).rejects.toThrow(
- 'No endpoint provided',
- );
- });
-
- it('should throw error for invalid argument schema', async () => {
- await expect(
- toolsMap.invoke_api_endpoint.handler(fakeClient, {
- endpoint_name: 'test_read_endpoint',
- args: { wrongParam: 'test value' }, // Missing required testParam
- }),
- ).rejects.toThrow(/Invalid arguments for endpoint/);
- });
- });
-
- function toolOrError(name: string) {
- const tool = tools.find((tool) => tool.tool.name === name);
- if (!tool) throw new Error(`Tool ${name} not found`);
- return tool;
- }
-});
-
-function makeEndpoint(
- name: string,
- resource: string,
- operation: 'read' | 'write',
- tags: string[] = [],
-): Endpoint {
- return {
- metadata: {
- resource,
- operation,
- tags,
- },
- tool: {
- name,
- description: `Test endpoint for ${name}`,
- inputSchema: {
- type: 'object',
- properties: {
- testParam: { type: 'string' },
- },
- required: ['testParam'],
- },
- },
- handler: jest.fn().mockResolvedValue({ success: true }),
- };
-}
diff --git a/packages/mcp-server/tests/options.test.ts b/packages/mcp-server/tests/options.test.ts
index a8a5b81a..532666a8 100644
--- a/packages/mcp-server/tests/options.test.ts
+++ b/packages/mcp-server/tests/options.test.ts
@@ -1,6 +1,4 @@
import { parseCLIOptions, parseQueryOptions } from '../src/options';
-import { Filter } from '../src/tools';
-import { parseEmbeddedJSON } from '../src/compat';
// Mock process.argv
const mockArgv = (args: string[]) => {
@@ -12,337 +10,35 @@ const mockArgv = (args: string[]) => {
};
describe('parseCLIOptions', () => {
- it('should parse basic filter options', () => {
- const cleanup = mockArgv([
- '--tool=test-tool',
- '--resource=test-resource',
- '--operation=read',
- '--tag=test-tag',
- ]);
+ it('default parsing should be stdio', () => {
+ const cleanup = mockArgv([]);
const result = parseCLIOptions();
- expect(result.filters).toEqual([
- { type: 'tag', op: 'include', value: 'test-tag' },
- { type: 'resource', op: 'include', value: 'test-resource' },
- { type: 'tool', op: 'include', value: 'test-tool' },
- { type: 'operation', op: 'include', value: 'read' },
- ] as Filter[]);
-
- expect(result.capabilities).toEqual({});
-
- expect(result.list).toBe(false);
-
- cleanup();
- });
-
- it('should parse exclusion filters', () => {
- const cleanup = mockArgv([
- '--no-tool=exclude-tool',
- '--no-resource=exclude-resource',
- '--no-operation=write',
- '--no-tag=exclude-tag',
- ]);
-
- const result = parseCLIOptions();
-
- expect(result.filters).toEqual([
- { type: 'tag', op: 'exclude', value: 'exclude-tag' },
- { type: 'resource', op: 'exclude', value: 'exclude-resource' },
- { type: 'tool', op: 'exclude', value: 'exclude-tool' },
- { type: 'operation', op: 'exclude', value: 'write' },
- ] as Filter[]);
-
- expect(result.capabilities).toEqual({});
-
- cleanup();
- });
-
- it('should parse client presets', () => {
- const cleanup = mockArgv(['--client=openai-agents']);
-
- const result = parseCLIOptions();
-
- expect(result.client).toEqual('openai-agents');
-
- cleanup();
- });
-
- it('should parse individual capabilities', () => {
- const cleanup = mockArgv([
- '--capability=top-level-unions',
- '--capability=valid-json',
- '--capability=refs',
- '--capability=unions',
- '--capability=tool-name-length=40',
- ]);
-
- const result = parseCLIOptions();
-
- expect(result.capabilities).toEqual({
- topLevelUnions: true,
- validJson: true,
- refs: true,
- unions: true,
- toolNameLength: 40,
- });
-
- cleanup();
- });
-
- it('should handle list option', () => {
- const cleanup = mockArgv(['--list']);
-
- const result = parseCLIOptions();
-
- expect(result.list).toBe(true);
-
- cleanup();
- });
-
- it('should handle multiple filters of the same type', () => {
- const cleanup = mockArgv(['--tool=tool1', '--tool=tool2', '--resource=res1', '--resource=res2']);
-
- const result = parseCLIOptions();
-
- expect(result.filters).toEqual([
- { type: 'resource', op: 'include', value: 'res1' },
- { type: 'resource', op: 'include', value: 'res2' },
- { type: 'tool', op: 'include', value: 'tool1' },
- { type: 'tool', op: 'include', value: 'tool2' },
- ] as Filter[]);
+ expect(result.transport).toBe('stdio');
cleanup();
});
- it('should handle comma-separated values in array options', () => {
- const cleanup = mockArgv([
- '--tool=tool1,tool2',
- '--resource=res1,res2',
- '--capability=top-level-unions,valid-json,unions',
- ]);
+ it('using http transport with a port', () => {
+ const cleanup = mockArgv(['--transport=http', '--port=2222']);
const result = parseCLIOptions();
- expect(result.filters).toEqual([
- { type: 'resource', op: 'include', value: 'res1' },
- { type: 'resource', op: 'include', value: 'res2' },
- { type: 'tool', op: 'include', value: 'tool1' },
- { type: 'tool', op: 'include', value: 'tool2' },
- ] as Filter[]);
-
- expect(result.capabilities).toEqual({
- topLevelUnions: true,
- validJson: true,
- unions: true,
- });
-
- cleanup();
- });
-
- it('should handle invalid tool-name-length format', () => {
- const cleanup = mockArgv(['--capability=tool-name-length=invalid']);
-
- // Mock console.error to prevent output during test
- const originalError = console.error;
- console.error = jest.fn();
-
- expect(() => parseCLIOptions()).toThrow();
-
- console.error = originalError;
- cleanup();
- });
-
- it('should handle unknown capability', () => {
- const cleanup = mockArgv(['--capability=unknown-capability']);
-
- // Mock console.error to prevent output during test
- const originalError = console.error;
- console.error = jest.fn();
-
- expect(() => parseCLIOptions()).toThrow();
-
- console.error = originalError;
+ expect(result.transport).toBe('http');
+ expect(result.port).toBe('2222');
cleanup();
});
});
describe('parseQueryOptions', () => {
- const defaultOptions = {
- client: undefined,
- includeDynamicTools: undefined,
- includeAllTools: undefined,
- filters: [],
- capabilities: {
- topLevelUnions: true,
- validJson: true,
- refs: true,
- unions: true,
- formats: true,
- toolNameLength: undefined,
- },
- };
-
- it('should parse basic filter options from query string', () => {
- const query = 'tool=test-tool&resource=test-resource&operation=read&tag=test-tag';
- const result = parseQueryOptions(defaultOptions, query);
-
- expect(result.filters).toEqual([
- { type: 'resource', op: 'include', value: 'test-resource' },
- { type: 'operation', op: 'include', value: 'read' },
- { type: 'tag', op: 'include', value: 'test-tag' },
- { type: 'tool', op: 'include', value: 'test-tool' },
- ]);
-
- expect(result.capabilities).toEqual({
- topLevelUnions: true,
- validJson: true,
- refs: true,
- unions: true,
- formats: true,
- toolNameLength: undefined,
- });
- });
-
- it('should parse exclusion filters from query string', () => {
- const query = 'no_tool=exclude-tool&no_resource=exclude-resource&no_operation=write&no_tag=exclude-tag';
- const result = parseQueryOptions(defaultOptions, query);
-
- expect(result.filters).toEqual([
- { type: 'resource', op: 'exclude', value: 'exclude-resource' },
- { type: 'operation', op: 'exclude', value: 'write' },
- { type: 'tag', op: 'exclude', value: 'exclude-tag' },
- { type: 'tool', op: 'exclude', value: 'exclude-tool' },
- ]);
- });
-
- it('should parse client option from query string', () => {
- const query = 'client=openai-agents';
- const result = parseQueryOptions(defaultOptions, query);
-
- expect(result.client).toBe('openai-agents');
- });
-
- it('should parse client capabilities from query string', () => {
- const query = 'capability=top-level-unions&capability=valid-json&capability=tool-name-length%3D40';
- const result = parseQueryOptions(defaultOptions, query);
+ const defaultOptions = {};
- expect(result.capabilities).toEqual({
- topLevelUnions: true,
- validJson: true,
- refs: true,
- unions: true,
- formats: true,
- toolNameLength: 40,
- });
- });
-
- it('should parse no-capability options from query string', () => {
- const query = 'no_capability=top-level-unions&no_capability=refs&no_capability=formats';
- const result = parseQueryOptions(defaultOptions, query);
-
- expect(result.capabilities).toEqual({
- topLevelUnions: false,
- validJson: true,
- refs: false,
- unions: true,
- formats: false,
- toolNameLength: undefined,
- });
- });
-
- it('should parse tools options from query string', () => {
- const query = 'tools=dynamic&tools=all';
- const result = parseQueryOptions(defaultOptions, query);
-
- expect(result.includeDynamicTools).toBe(true);
- expect(result.includeAllTools).toBe(true);
- });
-
- it('should parse no-tools options from query string', () => {
- const query = 'tools=dynamic&tools=all&no_tools=dynamic';
- const result = parseQueryOptions(defaultOptions, query);
-
- expect(result.includeDynamicTools).toBe(false);
- expect(result.includeAllTools).toBe(true);
- });
-
- it('should handle array values in query string', () => {
- const query = 'tool[]=tool1&tool[]=tool2&resource[]=res1&resource[]=res2';
- const result = parseQueryOptions(defaultOptions, query);
-
- expect(result.filters).toEqual([
- { type: 'resource', op: 'include', value: 'res1' },
- { type: 'resource', op: 'include', value: 'res2' },
- { type: 'tool', op: 'include', value: 'tool1' },
- { type: 'tool', op: 'include', value: 'tool2' },
- ]);
- });
-
- it('should merge with default options', () => {
- const defaultWithFilters = {
- ...defaultOptions,
- filters: [{ type: 'tag' as const, op: 'include' as const, value: 'existing-tag' }],
- client: 'cursor' as const,
- includeDynamicTools: true,
- };
-
- const query = 'tool=new-tool&resource=new-resource';
- const result = parseQueryOptions(defaultWithFilters, query);
-
- expect(result.filters).toEqual([
- { type: 'tag', op: 'include', value: 'existing-tag' },
- { type: 'resource', op: 'include', value: 'new-resource' },
- { type: 'tool', op: 'include', value: 'new-tool' },
- ]);
-
- expect(result.client).toBe('cursor');
- expect(result.includeDynamicTools).toBe(true);
- });
-
- it('should override client from default options', () => {
- const defaultWithClient = {
- ...defaultOptions,
- client: 'cursor' as const,
- };
-
- const query = 'client=openai-agents';
- const result = parseQueryOptions(defaultWithClient, query);
-
- expect(result.client).toBe('openai-agents');
- });
-
- it('should merge capabilities with default options', () => {
- const defaultWithCapabilities = {
- ...defaultOptions,
- capabilities: {
- topLevelUnions: false,
- validJson: false,
- refs: true,
- unions: true,
- formats: true,
- toolNameLength: 30,
- },
- };
-
- const query = 'capability=top-level-unions&no_capability=refs';
- const result = parseQueryOptions(defaultWithCapabilities, query);
-
- expect(result.capabilities).toEqual({
- topLevelUnions: true,
- validJson: false,
- refs: false,
- unions: true,
- formats: true,
- toolNameLength: 30,
- });
- });
-
- it('should handle empty query string', () => {
+ it('default parsing should be empty', () => {
const query = '';
const result = parseQueryOptions(defaultOptions, query);
- expect(result).toEqual(defaultOptions);
+ expect(result).toBe({});
});
it('should handle invalid query string gracefully', () => {
@@ -351,168 +47,4 @@ describe('parseQueryOptions', () => {
// Should throw due to Zod validation for invalid operation
expect(() => parseQueryOptions(defaultOptions, query)).toThrow();
});
-
- it('should preserve default undefined values when not specified', () => {
- const defaultWithUndefined = {
- ...defaultOptions,
- client: undefined,
- includeDynamicTools: undefined,
- includeAllTools: undefined,
- };
-
- const query = 'tool=test-tool';
- const result = parseQueryOptions(defaultWithUndefined, query);
-
- expect(result.client).toBeUndefined();
- expect(result.includeDynamicTools).toBeFalsy();
- expect(result.includeAllTools).toBeFalsy();
- });
-
- it('should handle complex query with mixed include and exclude filters', () => {
- const query =
- 'tool=include-tool&no_tool=exclude-tool&resource=include-res&no_resource=exclude-res&operation=read&tag=include-tag&no_tag=exclude-tag';
- const result = parseQueryOptions(defaultOptions, query);
-
- expect(result.filters).toEqual([
- { type: 'resource', op: 'include', value: 'include-res' },
- { type: 'operation', op: 'include', value: 'read' },
- { type: 'tag', op: 'include', value: 'include-tag' },
- { type: 'tool', op: 'include', value: 'include-tool' },
- { type: 'resource', op: 'exclude', value: 'exclude-res' },
- { type: 'tag', op: 'exclude', value: 'exclude-tag' },
- { type: 'tool', op: 'exclude', value: 'exclude-tool' },
- ]);
- });
-});
-
-describe('parseEmbeddedJSON', () => {
- it('should not change non-string values', () => {
- const args = {
- numberProp: 42,
- booleanProp: true,
- objectProp: { nested: 'value' },
- arrayProp: [1, 2, 3],
- nullProp: null,
- undefinedProp: undefined,
- };
- const schema = {};
-
- const result = parseEmbeddedJSON(args, schema);
-
- expect(result).toBe(args); // Should return original object since no changes made
- expect(result['numberProp']).toBe(42);
- expect(result['booleanProp']).toBe(true);
- expect(result['objectProp']).toEqual({ nested: 'value' });
- expect(result['arrayProp']).toEqual([1, 2, 3]);
- expect(result['nullProp']).toBe(null);
- expect(result['undefinedProp']).toBe(undefined);
- });
-
- it('should parse valid JSON objects in string properties', () => {
- const args = {
- jsonObjectString: '{"key": "value", "number": 123}',
- regularString: 'not json',
- };
- const schema = {};
-
- const result = parseEmbeddedJSON(args, schema);
-
- expect(result).not.toBe(args); // Should return new object since changes were made
- expect(result['jsonObjectString']).toEqual({ key: 'value', number: 123 });
- expect(result['regularString']).toBe('not json');
- });
-
- it('should leave invalid JSON in string properties unchanged', () => {
- const args = {
- invalidJson1: '{"key": value}', // Missing quotes around value
- invalidJson2: '{key: "value"}', // Missing quotes around key
- invalidJson3: '{"key": "value",}', // Trailing comma
- invalidJson4: 'just a regular string',
- emptyString: '',
- };
- const schema = {};
-
- const result = parseEmbeddedJSON(args, schema);
-
- expect(result).toBe(args); // Should return original object since no changes made
- expect(result['invalidJson1']).toBe('{"key": value}');
- expect(result['invalidJson2']).toBe('{key: "value"}');
- expect(result['invalidJson3']).toBe('{"key": "value",}');
- expect(result['invalidJson4']).toBe('just a regular string');
- expect(result['emptyString']).toBe('');
- });
-
- it('should not parse JSON primitives in string properties', () => {
- const args = {
- numberString: '123',
- floatString: '45.67',
- negativeNumberString: '-89',
- booleanTrueString: 'true',
- booleanFalseString: 'false',
- nullString: 'null',
- jsonArrayString: '[1, 2, 3, "test"]',
- regularString: 'not json',
- };
- const schema = {};
-
- const result = parseEmbeddedJSON(args, schema);
-
- expect(result).toBe(args); // Should return original object since no changes made
- expect(result['numberString']).toBe('123');
- expect(result['floatString']).toBe('45.67');
- expect(result['negativeNumberString']).toBe('-89');
- expect(result['booleanTrueString']).toBe('true');
- expect(result['booleanFalseString']).toBe('false');
- expect(result['nullString']).toBe('null');
- expect(result['jsonArrayString']).toBe('[1, 2, 3, "test"]');
- expect(result['regularString']).toBe('not json');
- });
-
- it('should handle mixed valid objects and other JSON types', () => {
- const args = {
- validObject: '{"success": true}',
- invalidObject: '{"missing": quote}',
- validNumber: '42',
- validArray: '[1, 2, 3]',
- keepAsString: 'hello world',
- nonString: 123,
- };
- const schema = {};
-
- const result = parseEmbeddedJSON(args, schema);
-
- expect(result).not.toBe(args); // Should return new object since some changes were made
- expect(result['validObject']).toEqual({ success: true });
- expect(result['invalidObject']).toBe('{"missing": quote}');
- expect(result['validNumber']).toBe('42'); // Not parsed, remains string
- expect(result['validArray']).toBe('[1, 2, 3]'); // Not parsed, remains string
- expect(result['keepAsString']).toBe('hello world');
- expect(result['nonString']).toBe(123);
- });
-
- it('should return original object when no strings are present', () => {
- const args = {
- number: 42,
- boolean: true,
- object: { key: 'value' },
- };
- const schema = {};
-
- const result = parseEmbeddedJSON(args, schema);
-
- expect(result).toBe(args); // Should return original object since no changes made
- });
-
- it('should return original object when all strings are invalid JSON', () => {
- const args = {
- string1: 'hello',
- string2: 'world',
- string3: 'not json at all',
- };
- const schema = {};
-
- const result = parseEmbeddedJSON(args, schema);
-
- expect(result).toBe(args); // Should return original object since no changes made
- });
});
diff --git a/packages/mcp-server/tests/tools.test.ts b/packages/mcp-server/tests/tools.test.ts
deleted file mode 100644
index cfff24a2..00000000
--- a/packages/mcp-server/tests/tools.test.ts
+++ /dev/null
@@ -1,225 +0,0 @@
-import { Endpoint, Filter, Metadata, query } from '../src/tools';
-
-describe('Endpoint filtering', () => {
- const endpoints: Endpoint[] = [
- endpoint({
- resource: 'user',
- operation: 'read',
- tags: ['admin'],
- toolName: 'retrieve_user',
- }),
- endpoint({
- resource: 'user.profile',
- operation: 'write',
- tags: [],
- toolName: 'create_user_profile',
- }),
- endpoint({
- resource: 'user.profile',
- operation: 'read',
- tags: [],
- toolName: 'get_user_profile',
- }),
- endpoint({
- resource: 'user.roles.permissions',
- operation: 'write',
- tags: ['admin', 'security'],
- toolName: 'update_user_role_permissions',
- }),
- endpoint({
- resource: 'documents.metadata.tags',
- operation: 'write',
- tags: ['taxonomy', 'metadata'],
- toolName: 'create_document_metadata_tags',
- }),
- endpoint({
- resource: 'organization.settings',
- operation: 'read',
- tags: ['admin', 'configuration'],
- toolName: 'get_organization_settings',
- }),
- ];
-
- const tests: { name: string; filters: Filter[]; expected: string[] }[] = [
- {
- name: 'match none',
- filters: [],
- expected: [],
- },
-
- // Resource tests
- {
- name: 'simple resource',
- filters: [{ type: 'resource', op: 'include', value: 'user' }],
- expected: ['retrieve_user'],
- },
- {
- name: 'exclude resource',
- filters: [{ type: 'resource', op: 'exclude', value: 'user' }],
- expected: [
- 'create_user_profile',
- 'get_user_profile',
- 'update_user_role_permissions',
- 'create_document_metadata_tags',
- 'get_organization_settings',
- ],
- },
- {
- name: 'resource and subresources',
- filters: [{ type: 'resource', op: 'include', value: 'user*' }],
- expected: ['retrieve_user', 'create_user_profile', 'get_user_profile', 'update_user_role_permissions'],
- },
- {
- name: 'just subresources',
- filters: [{ type: 'resource', op: 'include', value: 'user.*' }],
- expected: ['create_user_profile', 'get_user_profile', 'update_user_role_permissions'],
- },
- {
- name: 'specific subresource',
- filters: [{ type: 'resource', op: 'include', value: 'user.roles.permissions' }],
- expected: ['update_user_role_permissions'],
- },
- {
- name: 'deep wildcard match',
- filters: [{ type: 'resource', op: 'include', value: '*.*.tags' }],
- expected: ['create_document_metadata_tags'],
- },
-
- // Operation tests
- {
- name: 'read operation',
- filters: [{ type: 'operation', op: 'include', value: 'read' }],
- expected: ['retrieve_user', 'get_user_profile', 'get_organization_settings'],
- },
- {
- name: 'write operation',
- filters: [{ type: 'operation', op: 'include', value: 'write' }],
- expected: ['create_user_profile', 'update_user_role_permissions', 'create_document_metadata_tags'],
- },
- {
- name: 'resource and operation combined',
- filters: [
- { type: 'resource', op: 'include', value: 'user.profile' },
- { type: 'operation', op: 'exclude', value: 'write' },
- ],
- expected: ['get_user_profile'],
- },
-
- // Tag tests
- {
- name: 'admin tag',
- filters: [{ type: 'tag', op: 'include', value: 'admin' }],
- expected: ['retrieve_user', 'update_user_role_permissions', 'get_organization_settings'],
- },
- {
- name: 'taxonomy tag',
- filters: [{ type: 'tag', op: 'include', value: 'taxonomy' }],
- expected: ['create_document_metadata_tags'],
- },
- {
- name: 'multiple tags (OR logic)',
- filters: [
- { type: 'tag', op: 'include', value: 'admin' },
- { type: 'tag', op: 'include', value: 'security' },
- ],
- expected: ['retrieve_user', 'update_user_role_permissions', 'get_organization_settings'],
- },
- {
- name: 'excluding a tag',
- filters: [
- { type: 'tag', op: 'include', value: 'admin' },
- { type: 'tag', op: 'exclude', value: 'security' },
- ],
- expected: ['retrieve_user', 'get_organization_settings'],
- },
-
- // Tool name tests
- {
- name: 'tool name match',
- filters: [{ type: 'tool', op: 'include', value: 'get_organization_settings' }],
- expected: ['get_organization_settings'],
- },
- {
- name: 'two tools match',
- filters: [
- { type: 'tool', op: 'include', value: 'get_organization_settings' },
- { type: 'tool', op: 'include', value: 'create_user_profile' },
- ],
- expected: ['create_user_profile', 'get_organization_settings'],
- },
- {
- name: 'excluding tool by name',
- filters: [
- { type: 'resource', op: 'include', value: 'user*' },
- { type: 'tool', op: 'exclude', value: 'retrieve_user' },
- ],
- expected: ['create_user_profile', 'get_user_profile', 'update_user_role_permissions'],
- },
-
- // Complex combinations
- {
- name: 'complex filter: read operations with admin tag',
- filters: [
- { type: 'operation', op: 'include', value: 'read' },
- { type: 'tag', op: 'include', value: 'admin' },
- ],
- expected: [
- 'retrieve_user',
- 'get_user_profile',
- 'update_user_role_permissions',
- 'get_organization_settings',
- ],
- },
- {
- name: 'complex filter: user resources with no tags',
- filters: [
- { type: 'resource', op: 'include', value: 'user.profile' },
- { type: 'tag', op: 'exclude', value: 'admin' },
- ],
- expected: ['create_user_profile', 'get_user_profile'],
- },
- {
- name: 'complex filter: user resources and tags',
- filters: [
- { type: 'resource', op: 'include', value: 'user.profile' },
- { type: 'tag', op: 'include', value: 'admin' },
- ],
- expected: [
- 'retrieve_user',
- 'create_user_profile',
- 'get_user_profile',
- 'update_user_role_permissions',
- 'get_organization_settings',
- ],
- },
- ];
-
- tests.forEach((test) => {
- it(`filters by ${test.name}`, () => {
- const filtered = query(test.filters, endpoints);
- expect(filtered.map((e) => e.tool.name)).toEqual(test.expected);
- });
- });
-});
-
-function endpoint({
- resource,
- operation,
- tags,
- toolName,
-}: {
- resource: string;
- operation: Metadata['operation'];
- tags: string[];
- toolName: string;
-}): Endpoint {
- return {
- metadata: {
- resource,
- operation,
- tags,
- },
- tool: { name: toolName, inputSchema: { type: 'object', properties: {} } },
- handler: jest.fn(),
- };
-}
diff --git a/packages/mcp-server/yarn.lock b/packages/mcp-server/yarn.lock
index 966d0575..38be884f 100644
--- a/packages/mcp-server/yarn.lock
+++ b/packages/mcp-server/yarn.lock
@@ -10,6 +10,20 @@
"@jridgewell/gen-mapping" "^0.3.5"
"@jridgewell/trace-mapping" "^0.3.24"
+"@anthropic-ai/mcpb@1.1.0":
+ version "1.1.0"
+ resolved "https://registry.yarnpkg.com/@anthropic-ai/mcpb/-/mcpb-1.1.0.tgz#1af18de2ab9499d321d6310d0be095f5fef5161b"
+ integrity sha512-nOnhG1eNpGKSIDv6lt3xsI3w2p2k0D/rPTMGXXugLovCEaJ7svh8XMfCe145vs8qo384t8wKbokWAvx9PkQMDA==
+ dependencies:
+ "@inquirer/prompts" "^6.0.1"
+ commander "^13.1.0"
+ fflate "^0.8.2"
+ galactus "^1.0.0"
+ ignore "^7.0.5"
+ node-forge "^1.3.1"
+ pretty-bytes "^5.6.0"
+ zod "^3.25.67"
+
"@babel/code-frame@^7.0.0", "@babel/code-frame@^7.12.13", "@babel/code-frame@^7.27.1":
version "7.27.1"
resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.27.1.tgz#200f715e66d52a23b221a9435534a91cc13ad5be"
@@ -336,6 +350,144 @@
resolved "https://registry.yarnpkg.com/@humanwhocodes/object-schema/-/object-schema-2.0.3.tgz#4a2868d75d6d6963e423bcf90b7fd1be343409d3"
integrity sha512-93zYdMES/c1D69yZiKDBj0V24vqNzB/koF26KPaagAfd3P/4gUlh3Dys5ogAK+Exi9QyzlD8x/08Zt7wIKcDcA==
+"@inquirer/checkbox@^3.0.1":
+ version "3.0.1"
+ resolved "https://registry.yarnpkg.com/@inquirer/checkbox/-/checkbox-3.0.1.tgz#0a57f704265f78c36e17f07e421b98efb4b9867b"
+ integrity sha512-0hm2nrToWUdD6/UHnel/UKGdk1//ke5zGUpHIvk5ZWmaKezlGxZkOJXNSWsdxO/rEqTkbB3lNC2J6nBElV2aAQ==
+ dependencies:
+ "@inquirer/core" "^9.2.1"
+ "@inquirer/figures" "^1.0.6"
+ "@inquirer/type" "^2.0.0"
+ ansi-escapes "^4.3.2"
+ yoctocolors-cjs "^2.1.2"
+
+"@inquirer/confirm@^4.0.1":
+ version "4.0.1"
+ resolved "https://registry.yarnpkg.com/@inquirer/confirm/-/confirm-4.0.1.tgz#9106d6bffa0b2fdd0e4f60319b6f04f2e06e6e25"
+ integrity sha512-46yL28o2NJ9doViqOy0VDcoTzng7rAb6yPQKU7VDLqkmbCaH4JqK4yk4XqlzNWy9PVC5pG1ZUXPBQv+VqnYs2w==
+ dependencies:
+ "@inquirer/core" "^9.2.1"
+ "@inquirer/type" "^2.0.0"
+
+"@inquirer/core@^9.2.1":
+ version "9.2.1"
+ resolved "https://registry.yarnpkg.com/@inquirer/core/-/core-9.2.1.tgz#677c49dee399c9063f31e0c93f0f37bddc67add1"
+ integrity sha512-F2VBt7W/mwqEU4bL0RnHNZmC/OxzNx9cOYxHqnXX3MP6ruYvZUZAW9imgN9+h/uBT/oP8Gh888J2OZSbjSeWcg==
+ dependencies:
+ "@inquirer/figures" "^1.0.6"
+ "@inquirer/type" "^2.0.0"
+ "@types/mute-stream" "^0.0.4"
+ "@types/node" "^22.5.5"
+ "@types/wrap-ansi" "^3.0.0"
+ ansi-escapes "^4.3.2"
+ cli-width "^4.1.0"
+ mute-stream "^1.0.0"
+ signal-exit "^4.1.0"
+ strip-ansi "^6.0.1"
+ wrap-ansi "^6.2.0"
+ yoctocolors-cjs "^2.1.2"
+
+"@inquirer/editor@^3.0.1":
+ version "3.0.1"
+ resolved "https://registry.yarnpkg.com/@inquirer/editor/-/editor-3.0.1.tgz#d109f21e050af6b960725388cb1c04214ed7c7bc"
+ integrity sha512-VA96GPFaSOVudjKFraokEEmUQg/Lub6OXvbIEZU1SDCmBzRkHGhxoFAVaF30nyiB4m5cEbDgiI2QRacXZ2hw9Q==
+ dependencies:
+ "@inquirer/core" "^9.2.1"
+ "@inquirer/type" "^2.0.0"
+ external-editor "^3.1.0"
+
+"@inquirer/expand@^3.0.1":
+ version "3.0.1"
+ resolved "https://registry.yarnpkg.com/@inquirer/expand/-/expand-3.0.1.tgz#aed9183cac4d12811be47a4a895ea8e82a17e22c"
+ integrity sha512-ToG8d6RIbnVpbdPdiN7BCxZGiHOTomOX94C2FaT5KOHupV40tKEDozp12res6cMIfRKrXLJyexAZhWVHgbALSQ==
+ dependencies:
+ "@inquirer/core" "^9.2.1"
+ "@inquirer/type" "^2.0.0"
+ yoctocolors-cjs "^2.1.2"
+
+"@inquirer/figures@^1.0.6":
+ version "1.0.15"
+ resolved "https://registry.yarnpkg.com/@inquirer/figures/-/figures-1.0.15.tgz#dbb49ed80df11df74268023b496ac5d9acd22b3a"
+ integrity sha512-t2IEY+unGHOzAaVM5Xx6DEWKeXlDDcNPeDyUpsRc6CUhBfU3VQOEl+Vssh7VNp1dR8MdUJBWhuObjXCsVpjN5g==
+
+"@inquirer/input@^3.0.1":
+ version "3.0.1"
+ resolved "https://registry.yarnpkg.com/@inquirer/input/-/input-3.0.1.tgz#de63d49e516487388508d42049deb70f2cb5f28e"
+ integrity sha512-BDuPBmpvi8eMCxqC5iacloWqv+5tQSJlUafYWUe31ow1BVXjW2a5qe3dh4X/Z25Wp22RwvcaLCc2siHobEOfzg==
+ dependencies:
+ "@inquirer/core" "^9.2.1"
+ "@inquirer/type" "^2.0.0"
+
+"@inquirer/number@^2.0.1":
+ version "2.0.1"
+ resolved "https://registry.yarnpkg.com/@inquirer/number/-/number-2.0.1.tgz#b9863080d02ab7dc2e56e16433d83abea0f2a980"
+ integrity sha512-QpR8jPhRjSmlr/mD2cw3IR8HRO7lSVOnqUvQa8scv1Lsr3xoAMMworcYW3J13z3ppjBFBD2ef1Ci6AE5Qn8goQ==
+ dependencies:
+ "@inquirer/core" "^9.2.1"
+ "@inquirer/type" "^2.0.0"
+
+"@inquirer/password@^3.0.1":
+ version "3.0.1"
+ resolved "https://registry.yarnpkg.com/@inquirer/password/-/password-3.0.1.tgz#2a9a9143591088336bbd573bcb05d5bf080dbf87"
+ integrity sha512-haoeEPUisD1NeE2IanLOiFr4wcTXGWrBOyAyPZi1FfLJuXOzNmxCJPgUrGYKVh+Y8hfGJenIfz5Wb/DkE9KkMQ==
+ dependencies:
+ "@inquirer/core" "^9.2.1"
+ "@inquirer/type" "^2.0.0"
+ ansi-escapes "^4.3.2"
+
+"@inquirer/prompts@^6.0.1":
+ version "6.0.1"
+ resolved "https://registry.yarnpkg.com/@inquirer/prompts/-/prompts-6.0.1.tgz#43f5c0ed35c5ebfe52f1d43d46da2d363d950071"
+ integrity sha512-yl43JD/86CIj3Mz5mvvLJqAOfIup7ncxfJ0Btnl0/v5TouVUyeEdcpknfgc+yMevS/48oH9WAkkw93m7otLb/A==
+ dependencies:
+ "@inquirer/checkbox" "^3.0.1"
+ "@inquirer/confirm" "^4.0.1"
+ "@inquirer/editor" "^3.0.1"
+ "@inquirer/expand" "^3.0.1"
+ "@inquirer/input" "^3.0.1"
+ "@inquirer/number" "^2.0.1"
+ "@inquirer/password" "^3.0.1"
+ "@inquirer/rawlist" "^3.0.1"
+ "@inquirer/search" "^2.0.1"
+ "@inquirer/select" "^3.0.1"
+
+"@inquirer/rawlist@^3.0.1":
+ version "3.0.1"
+ resolved "https://registry.yarnpkg.com/@inquirer/rawlist/-/rawlist-3.0.1.tgz#729def358419cc929045f264131878ed379e0af3"
+ integrity sha512-VgRtFIwZInUzTiPLSfDXK5jLrnpkuSOh1ctfaoygKAdPqjcjKYmGh6sCY1pb0aGnCGsmhUxoqLDUAU0ud+lGXQ==
+ dependencies:
+ "@inquirer/core" "^9.2.1"
+ "@inquirer/type" "^2.0.0"
+ yoctocolors-cjs "^2.1.2"
+
+"@inquirer/search@^2.0.1":
+ version "2.0.1"
+ resolved "https://registry.yarnpkg.com/@inquirer/search/-/search-2.0.1.tgz#69b774a0a826de2e27b48981d01bc5ad81e73721"
+ integrity sha512-r5hBKZk3g5MkIzLVoSgE4evypGqtOannnB3PKTG9NRZxyFRKcfzrdxXXPcoJQsxJPzvdSU2Rn7pB7lw0GCmGAg==
+ dependencies:
+ "@inquirer/core" "^9.2.1"
+ "@inquirer/figures" "^1.0.6"
+ "@inquirer/type" "^2.0.0"
+ yoctocolors-cjs "^2.1.2"
+
+"@inquirer/select@^3.0.1":
+ version "3.0.1"
+ resolved "https://registry.yarnpkg.com/@inquirer/select/-/select-3.0.1.tgz#1df9ed27fb85a5f526d559ac5ce7cc4e9dc4e7ec"
+ integrity sha512-lUDGUxPhdWMkN/fHy1Lk7pF3nK1fh/gqeyWXmctefhxLYxlDsc7vsPBEpxrfVGDsVdyYJsiJoD4bJ1b623cV1Q==
+ dependencies:
+ "@inquirer/core" "^9.2.1"
+ "@inquirer/figures" "^1.0.6"
+ "@inquirer/type" "^2.0.0"
+ ansi-escapes "^4.3.2"
+ yoctocolors-cjs "^2.1.2"
+
+"@inquirer/type@^2.0.0":
+ version "2.0.0"
+ resolved "https://registry.yarnpkg.com/@inquirer/type/-/type-2.0.0.tgz#08fa513dca2cb6264fe1b0a2fabade051444e3f6"
+ integrity sha512-XvJRx+2KR3YXyYtPUUy+qd9i7p+GO9Ko6VIIpWlBrpWwXDv8WLFeHTxz35CfQFUiBMLXlGHhGzys7lqit9gWag==
+ dependencies:
+ mute-stream "^1.0.0"
+
"@istanbuljs/load-nyc-config@^1.0.0":
version "1.1.0"
resolved "https://registry.yarnpkg.com/@istanbuljs/load-nyc-config/-/load-nyc-config-1.1.0.tgz#fd3db1d59ecf7cf121e80650bb86712f9b55eced"
@@ -584,12 +736,13 @@
"@jridgewell/resolve-uri" "^3.1.0"
"@jridgewell/sourcemap-codec" "^1.4.14"
-"@modelcontextprotocol/sdk@^1.11.5":
- version "1.17.3"
- resolved "https://registry.yarnpkg.com/@modelcontextprotocol/sdk/-/sdk-1.17.3.tgz#cf92354220f0183d28179e96a9bf3a8f6d3211ae"
- integrity sha512-JPwUKWSsbzx+DLFznf/QZ32Qa+ptfbUlHhRLrBQBAFu9iI1iYvizM4p+zhhRDceSsPutXp4z+R/HPVphlIiclg==
+"@modelcontextprotocol/sdk@^1.24.0":
+ version "1.24.3"
+ resolved "https://registry.yarnpkg.com/@modelcontextprotocol/sdk/-/sdk-1.24.3.tgz#81a3fcc919cb4ce8630e2bcecf59759176eb331a"
+ integrity sha512-YgSHW29fuzKKAHTGe9zjNoo+yF8KaQPzDC2W9Pv41E7/57IfY+AMGJ/aDFlgTLcVVELoggKE4syABCE75u3NCw==
dependencies:
- ajv "^6.12.6"
+ ajv "^8.17.1"
+ ajv-formats "^3.0.1"
content-type "^1.0.5"
cors "^2.8.5"
cross-spawn "^7.0.5"
@@ -597,10 +750,11 @@
eventsource-parser "^3.0.0"
express "^5.0.1"
express-rate-limit "^7.5.0"
+ jose "^6.1.1"
pkce-challenge "^5.0.0"
raw-body "^3.0.0"
- zod "^3.23.8"
- zod-to-json-schema "^3.24.1"
+ zod "^3.25 || ^4.0"
+ zod-to-json-schema "^3.25.0"
"@nodelib/fs.scandir@2.1.5":
version "2.1.5"
@@ -795,6 +949,13 @@
resolved "https://registry.yarnpkg.com/@types/mime/-/mime-1.3.5.tgz#1ef302e01cf7d2b5a0fa526790c9123bf1d06690"
integrity sha512-/pyBZWSLD2n0dcHE3hq8s8ZvcETHtEuF+3E7XVt0Ig2nvsVQXdghHVcEkIWjy9A0wKfTn97a/PSDYohKIlnP/w==
+"@types/mute-stream@^0.0.4":
+ version "0.0.4"
+ resolved "https://registry.yarnpkg.com/@types/mute-stream/-/mute-stream-0.0.4.tgz#77208e56a08767af6c5e1237be8888e2f255c478"
+ integrity sha512-CPM9nzrCPPJHQNA9keH9CVkVI+WR5kMa+7XEs5jcGQ0VoAGnLv242w8lIVgwAEfmE4oufJRaTc9PNLQl0ioAow==
+ dependencies:
+ "@types/node" "*"
+
"@types/node@*":
version "22.15.17"
resolved "https://registry.yarnpkg.com/@types/node/-/node-22.15.17.tgz#355ccec95f705b664e4332bb64a7f07db30b7055"
@@ -802,6 +963,13 @@
dependencies:
undici-types "~6.21.0"
+"@types/node@^22.5.5":
+ version "22.19.2"
+ resolved "https://registry.yarnpkg.com/@types/node/-/node-22.19.2.tgz#2f0956fba46518aaf7578c84e37bddab55f85d01"
+ integrity sha512-LPM2G3Syo1GLzXLGJAKdqoU35XvrWzGJ21/7sgZTUpbkBaOasTj8tjwn6w+hCkqaa1TfJ/w67rJSwYItlJ2mYw==
+ dependencies:
+ undici-types "~6.21.0"
+
"@types/qs@*", "@types/qs@^6.14.0":
version "6.14.0"
resolved "https://registry.yarnpkg.com/@types/qs/-/qs-6.14.0.tgz#d8b60cecf62f2db0fb68e5e006077b9178b85de5"
@@ -834,6 +1002,11 @@
resolved "https://registry.yarnpkg.com/@types/stack-utils/-/stack-utils-2.0.3.tgz#6209321eb2c1712a7e7466422b8cb1fc0d9dd5d8"
integrity sha512-9aEbYZ3TbYMznPdcdr3SmIrLXwC/AKZXQeCf9Pgao5CKb8CyHuEX5jzWPTkvregvhRJHcpRO6BFoGW9ycaOkYw==
+"@types/wrap-ansi@^3.0.0":
+ version "3.0.0"
+ resolved "https://registry.yarnpkg.com/@types/wrap-ansi/-/wrap-ansi-3.0.0.tgz#18b97a972f94f60a679fd5c796d96421b9abb9fd"
+ integrity sha512-ltIpx+kM7g/MLRZfkbL7EsCEjfzCcScLpkg37eXEtx5kmrAKBkTJwd1GIAjDSL8wTpM6Hzn5YO4pSb91BEwu1g==
+
"@types/yargs-parser@*":
version "21.0.3"
resolved "https://registry.yarnpkg.com/@types/yargs-parser/-/yargs-parser-21.0.3.tgz#815e30b786d2e8f0dcd85fd5bcf5e1a04d008f15"
@@ -970,7 +1143,14 @@ aggregate-error@^3.0.0:
clean-stack "^2.0.0"
indent-string "^4.0.0"
-ajv@^6.12.4, ajv@^6.12.6:
+ajv-formats@^3.0.1:
+ version "3.0.1"
+ resolved "https://registry.yarnpkg.com/ajv-formats/-/ajv-formats-3.0.1.tgz#3d5dc762bca17679c3c2ea7e90ad6b7532309578"
+ integrity sha512-8iUql50EUR+uUcdRQ3HDqa6EVyo3docL8g5WJ3FNcWmu62IbkGUue/pEyLBW8VGKKucTPgqeks4fIU1DA4yowQ==
+ dependencies:
+ ajv "^8.0.0"
+
+ajv@^6.12.4:
version "6.12.6"
resolved "https://registry.yarnpkg.com/ajv/-/ajv-6.12.6.tgz#baf5a62e802b07d977034586f8c3baf5adf26df4"
integrity sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==
@@ -980,7 +1160,17 @@ ajv@^6.12.4, ajv@^6.12.6:
json-schema-traverse "^0.4.1"
uri-js "^4.2.2"
-ansi-escapes@^4.2.1:
+ajv@^8.0.0, ajv@^8.17.1:
+ version "8.17.1"
+ resolved "https://registry.yarnpkg.com/ajv/-/ajv-8.17.1.tgz#37d9a5c776af6bc92d7f4f9510eba4c0a60d11a6"
+ integrity sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g==
+ dependencies:
+ fast-deep-equal "^3.1.3"
+ fast-uri "^3.0.1"
+ json-schema-traverse "^1.0.0"
+ require-from-string "^2.0.2"
+
+ansi-escapes@^4.2.1, ansi-escapes@^4.3.2:
version "4.3.2"
resolved "https://registry.yarnpkg.com/ansi-escapes/-/ansi-escapes-4.3.2.tgz#6b2291d1db7d98b6521d5f1efa42d0f3a9feb65e"
integrity sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ==
@@ -1222,6 +1412,11 @@ char-regex@^1.0.2:
resolved "https://registry.yarnpkg.com/char-regex/-/char-regex-1.0.2.tgz#d744358226217f981ed58f479b1d6bcc29545dcf"
integrity sha512-kWWXztvZ5SBQV+eRgKFeh8q5sLuZY2+8WUIzlxWVTg+oGwY14qylx1KbKzHd8P6ZYkAg0xyIDU9JMHhyJMZ1jw==
+chardet@^0.7.0:
+ version "0.7.0"
+ resolved "https://registry.yarnpkg.com/chardet/-/chardet-0.7.0.tgz#90094849f0937f2eedc2425d0d28a9e5f0cbad9e"
+ integrity sha512-mT8iDcrh03qDGRRmoA2hmBJnxpllMR+0/0qlzjqZES6NdiWDcZkCNAk4rPFZ9Q85r27unkiNNg8ZOiwZXBHwcA==
+
ci-info@^3.2.0:
version "3.9.0"
resolved "https://registry.yarnpkg.com/ci-info/-/ci-info-3.9.0.tgz#4279a62028a7b1f262f3473fc9605f5e218c59b4"
@@ -1237,6 +1432,11 @@ clean-stack@^2.0.0:
resolved "https://registry.yarnpkg.com/clean-stack/-/clean-stack-2.2.0.tgz#ee8472dbb129e727b31e8a10a427dee9dfe4008b"
integrity sha512-4diC9HaTE+KRAMWhDhrGOECgWZxoevMc5TlkObMqNSsVU62PYzXZ/SMTjzyGAFF1YusgxGcSWTEXBhp0CPwQ1A==
+cli-width@^4.1.0:
+ version "4.1.0"
+ resolved "https://registry.yarnpkg.com/cli-width/-/cli-width-4.1.0.tgz#42daac41d3c254ef38ad8ac037672130173691c5"
+ integrity sha512-ouuZd4/dm2Sw5Gmqy6bGyNNNe1qt9RpmxveLSO7KcgsTnU7RXfsw+/bukWGo1abgBiMAic068rclZsO4IWmmxQ==
+
cliui@^8.0.1:
version "8.0.1"
resolved "https://registry.yarnpkg.com/cliui/-/cliui-8.0.1.tgz#0c04b075db02cbfe60dc8e6cf2f5486b1a3608aa"
@@ -1273,6 +1473,11 @@ color-name@~1.1.4:
resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.4.tgz#c2a09a87acbde69543de6f63fa3995c826c536a2"
integrity sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==
+commander@^13.1.0:
+ version "13.1.0"
+ resolved "https://registry.yarnpkg.com/commander/-/commander-13.1.0.tgz#776167db68c78f38dcce1f9b8d7b8b9a488abf46"
+ integrity sha512-/rFeCpNJQbhSZjGVwO9RFV3xPqbnERS8MmIQzCtD/zl6gpJuV/bMLuN92oG3F7d8oDEHHRrujSXNUr8fpjntKw==
+
concat-map@0.0.1:
version "0.0.1"
resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b"
@@ -1685,6 +1890,15 @@ express@^5.0.1, express@^5.1.0:
type-is "^2.0.1"
vary "^1.1.2"
+external-editor@^3.1.0:
+ version "3.1.0"
+ resolved "https://registry.yarnpkg.com/external-editor/-/external-editor-3.1.0.tgz#cb03f740befae03ea4d283caed2741a83f335495"
+ integrity sha512-hMQ4CX1p1izmuLYyZqLMO/qGNw10wSv9QDCPfzXfyFrOaCSSoRfqE1Kf1s5an66J5JZC62NewG+mK49jOCtQew==
+ dependencies:
+ chardet "^0.7.0"
+ iconv-lite "^0.4.24"
+ tmp "^0.0.33"
+
fast-deep-equal@^3.1.1, fast-deep-equal@^3.1.3:
version "3.1.3"
resolved "https://registry.yarnpkg.com/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz#3a7d56b559d6cbc3eb512325244e619a65c6c525"
@@ -1716,6 +1930,11 @@ fast-levenshtein@^2.0.6:
resolved "https://registry.yarnpkg.com/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz#3d8a5c66883a16a30ca8643e851f19baa7797917"
integrity sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==
+fast-uri@^3.0.1:
+ version "3.1.0"
+ resolved "https://registry.yarnpkg.com/fast-uri/-/fast-uri-3.1.0.tgz#66eecff6c764c0df9b762e62ca7edcfb53b4edfa"
+ integrity sha512-iPeeDKJSWf4IEOasVVrknXpaBV0IApz/gp7S2bb7Z4Lljbl2MGJRqInZiUrQwV16cpzw/D3S5j5Julj/gT52AA==
+
fastq@^1.6.0:
version "1.19.1"
resolved "https://registry.yarnpkg.com/fastq/-/fastq-1.19.1.tgz#d50eaba803c8846a883c16492821ebcd2cda55f5"
@@ -1730,6 +1949,11 @@ fb-watchman@^2.0.0:
dependencies:
bser "2.1.1"
+fflate@^0.8.2:
+ version "0.8.2"
+ resolved "https://registry.yarnpkg.com/fflate/-/fflate-0.8.2.tgz#fc8631f5347812ad6028bbe4a2308b2792aa1dea"
+ integrity sha512-cPJU47OaAoCbg0pBvzsgpTPhmhqI5eJjh/JIu8tPj5q+T7iLvW/JAYUqmE7KOB4R1ZyEhzBaIQpQpardBF5z8A==
+
file-entry-cache@^6.0.1:
version "6.0.1"
resolved "https://registry.yarnpkg.com/file-entry-cache/-/file-entry-cache-6.0.1.tgz#211b2dd9659cb0394b073e7323ac3c933d522027"
@@ -1793,6 +2017,14 @@ flatted@^3.2.9:
resolved "https://registry.yarnpkg.com/flatted/-/flatted-3.3.3.tgz#67c8fad95454a7c7abebf74bb78ee74a44023358"
integrity sha512-GX+ysw4PBCz0PzosHDepZGANEuFCMLrnRTiEy9McGjmkCQYwRq4A/X786G/fjM/+OjsWSU1ZrY5qyARZmO/uwg==
+flora-colossus@^2.0.0:
+ version "2.0.0"
+ resolved "https://registry.yarnpkg.com/flora-colossus/-/flora-colossus-2.0.0.tgz#af1e85db0a8256ef05f3fb531c1235236c97220a"
+ integrity sha512-dz4HxH6pOvbUzZpZ/yXhafjbR2I8cenK5xL0KtBFb7U2ADsR+OwXifnxZjij/pZWF775uSCMzWVd+jDik2H2IA==
+ dependencies:
+ debug "^4.3.4"
+ fs-extra "^10.1.0"
+
forwarded@0.2.0:
version "0.2.0"
resolved "https://registry.yarnpkg.com/forwarded/-/forwarded-0.2.0.tgz#2269936428aad4c15c7ebe9779a84bf0b2a81811"
@@ -1803,6 +2035,15 @@ fresh@^2.0.0:
resolved "https://registry.yarnpkg.com/fresh/-/fresh-2.0.0.tgz#8dd7df6a1b3a1b3a5cf186c05a5dd267622635a4"
integrity sha512-Rx/WycZ60HOaqLKAi6cHRKKI7zxWbJ31MhntmtwMoaTeF7XFH9hhBp8vITaMidfljRQ6eYWCKkaTK+ykVJHP2A==
+fs-extra@^10.1.0:
+ version "10.1.0"
+ resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-10.1.0.tgz#02873cfbc4084dde127eaa5f9905eef2325d1abf"
+ integrity sha512-oRXApq54ETRj4eMiFzGnHWGy+zo5raudjuxN0b8H7s/RU2oW0Wvsx9O0ACRN/kRq9E8Vu/ReskGB5o3ji+FzHQ==
+ dependencies:
+ graceful-fs "^4.2.0"
+ jsonfile "^6.0.1"
+ universalify "^2.0.0"
+
fs.realpath@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f"
@@ -1818,6 +2059,20 @@ function-bind@^1.1.2:
resolved "https://registry.yarnpkg.com/function-bind/-/function-bind-1.1.2.tgz#2c02d864d97f3ea6c8830c464cbd11ab6eab7a1c"
integrity sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==
+fuse.js@^7.1.0:
+ version "7.1.0"
+ resolved "https://registry.yarnpkg.com/fuse.js/-/fuse.js-7.1.0.tgz#306228b4befeee11e05b027087c2744158527d09"
+ integrity sha512-trLf4SzuuUxfusZADLINj+dE8clK1frKdmqiJNb1Es75fmI5oY6X2mxLVUciLLjxqw/xr72Dhy+lER6dGd02FQ==
+
+galactus@^1.0.0:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/galactus/-/galactus-1.0.0.tgz#c2615182afa0c6d0859b92e56ae36d052827db7e"
+ integrity sha512-R1fam6D4CyKQGNlvJne4dkNF+PvUUl7TAJInvTGa9fti9qAv95quQz29GXapA4d8Ec266mJJxFVh82M4GIIGDQ==
+ dependencies:
+ debug "^4.3.4"
+ flora-colossus "^2.0.0"
+ fs-extra "^10.1.0"
+
gensync@^1.0.0-beta.2:
version "1.0.0-beta.2"
resolved "https://registry.yarnpkg.com/gensync/-/gensync-1.0.0-beta.2.tgz#32a6ee76c3d7f52d46b2b1ae5d93fea8580a25e0"
@@ -1910,7 +2165,7 @@ gopd@^1.2.0:
resolved "https://registry.yarnpkg.com/gopd/-/gopd-1.2.0.tgz#89f56b8217bdbc8802bd299df6d7f1081d7e51a1"
integrity sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==
-graceful-fs@^4.2.9:
+graceful-fs@^4.1.6, graceful-fs@^4.2.0, graceful-fs@^4.2.9:
version "4.2.11"
resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.11.tgz#4183e4e8bf08bb6e05bbb2f7d2e0c8f712ca40e3"
integrity sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==
@@ -1965,11 +2220,23 @@ iconv-lite@0.6.3, iconv-lite@^0.6.3:
dependencies:
safer-buffer ">= 2.1.2 < 3.0.0"
+iconv-lite@^0.4.24:
+ version "0.4.24"
+ resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.24.tgz#2022b4b25fbddc21d2f524974a474aafe733908b"
+ integrity sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==
+ dependencies:
+ safer-buffer ">= 2.1.2 < 3"
+
ignore@^5.2.0, ignore@^5.3.1:
version "5.3.2"
resolved "https://registry.yarnpkg.com/ignore/-/ignore-5.3.2.tgz#3cd40e729f3643fd87cb04e50bf0eb722bc596f5"
integrity sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==
+ignore@^7.0.5:
+ version "7.0.5"
+ resolved "https://registry.yarnpkg.com/ignore/-/ignore-7.0.5.tgz#4cb5f6cd7d4c7ab0365738c7aea888baa6d7efd9"
+ integrity sha512-Hs59xBNfUIunMFgWAbGX5cq6893IbWg4KnrjbYwX3tx0ztorVgTDA6B2sxf8ejHJ4wz8BqGUMYlnzNBer5NvGg==
+
import-fresh@^3.2.1:
version "3.3.1"
resolved "https://registry.yarnpkg.com/import-fresh/-/import-fresh-3.3.1.tgz#9cecb56503c0ada1f2741dbbd6546e4b13b57ccf"
@@ -2494,9 +2761,14 @@ jest@^29.4.0:
import-local "^3.0.2"
jest-cli "^29.7.0"
-"jq-web@https://github.com/stainless-api/jq-web/releases/download/v0.8.6/jq-web.tar.gz":
- version "0.8.6"
- resolved "https://github.com/stainless-api/jq-web/releases/download/v0.8.6/jq-web.tar.gz#14d0e126987736e82e964d675c3838b5944faa6f"
+jose@^6.1.1:
+ version "6.1.3"
+ resolved "https://registry.yarnpkg.com/jose/-/jose-6.1.3.tgz#8453d7be88af7bb7d64a0481d6a35a0145ba3ea5"
+ integrity sha512-0TpaTfihd4QMNwrz/ob2Bp7X04yuxJkjRGi4aKmOqwhov54i6u79oCv7T+C7lo70MKH6BesI3vscD1yb/yzKXQ==
+
+"jq-web@https://github.com/stainless-api/jq-web/releases/download/v0.8.8/jq-web.tar.gz":
+ version "0.8.8"
+ resolved "https://github.com/stainless-api/jq-web/releases/download/v0.8.8/jq-web.tar.gz#7849ef64bdfc28f70cbfc9888f886860e96da10d"
js-tokens@^4.0.0:
version "4.0.0"
@@ -2538,6 +2810,11 @@ json-schema-traverse@^0.4.1:
resolved "https://registry.yarnpkg.com/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz#69f6a87d9513ab8bb8fe63bdb0979c448e684660"
integrity sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==
+json-schema-traverse@^1.0.0:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz#ae7bcb3656ab77a73ba5c49bf654f38e6b6860e2"
+ integrity sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==
+
json-stable-stringify-without-jsonify@^1.0.1:
version "1.0.1"
resolved "https://registry.yarnpkg.com/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz#9db7b59496ad3f3cfef30a75142d2d930ad72651"
@@ -2548,6 +2825,15 @@ json5@^2.2.2, json5@^2.2.3:
resolved "https://registry.yarnpkg.com/json5/-/json5-2.2.3.tgz#78cd6f1a19bdc12b73db5ad0c61efd66c1e29283"
integrity sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==
+jsonfile@^6.0.1:
+ version "6.2.0"
+ resolved "https://registry.yarnpkg.com/jsonfile/-/jsonfile-6.2.0.tgz#7c265bd1b65de6977478300087c99f1c84383f62"
+ integrity sha512-FGuPw30AdOIUTRMC2OMRtQV+jkVj2cfPqSeWXv1NEAJ1qZ5zb1X6z1mFhbfOB/iy3ssJCD+3KuZ8r8C3uVFlAg==
+ dependencies:
+ universalify "^2.0.0"
+ optionalDependencies:
+ graceful-fs "^4.1.6"
+
keyv@^4.5.3:
version "4.5.4"
resolved "https://registry.yarnpkg.com/keyv/-/keyv-4.5.4.tgz#a879a99e29452f942439f2a405e3af8b31d4de93"
@@ -2721,6 +3007,11 @@ ms@^2.1.3:
resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.3.tgz#574c8138ce1d2b5861f0b44579dbadd60c6615b2"
integrity sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==
+mute-stream@^1.0.0:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/mute-stream/-/mute-stream-1.0.0.tgz#e31bd9fe62f0aed23520aa4324ea6671531e013e"
+ integrity sha512-avsJQhyd+680gKXyG/sQc0nXaC6rBkPOfyHYcFb9+hdkqQkR9bdnkJ0AMZhke0oesPqIO+mFFJ+IdBc7mst4IA==
+
natural-compare@^1.4.0:
version "1.4.0"
resolved "https://registry.yarnpkg.com/natural-compare/-/natural-compare-1.4.0.tgz#4abebfeed7541f2c27acfb29bdbbd15c8d5ba4f7"
@@ -2731,6 +3022,11 @@ negotiator@^1.0.0:
resolved "https://registry.yarnpkg.com/negotiator/-/negotiator-1.0.0.tgz#b6c91bb47172d69f93cfd7c357bbb529019b5f6a"
integrity sha512-8Ofs/AUQh8MaEcrlq5xOX0CQ9ypTF5dl78mjlMNfOK08fzpgTHQRQPBxcPlEtIw0yRpws+Zo/3r+5WRby7u3Gg==
+node-forge@^1.3.1:
+ version "1.3.3"
+ resolved "https://registry.yarnpkg.com/node-forge/-/node-forge-1.3.3.tgz#0ad80f6333b3a0045e827ac20b7f735f93716751"
+ integrity sha512-rLvcdSyRCyouf6jcOIPe/BgwG/d7hKjzMKOas33/pHEr6gbq18IK9zV7DiPvzsz0oBJPme6qr6H6kGZuI9/DZg==
+
node-int64@^0.4.0:
version "0.4.0"
resolved "https://registry.yarnpkg.com/node-int64/-/node-int64-0.4.0.tgz#87a9065cdb355d3182d8f94ce11188b825c68a3b"
@@ -2796,6 +3092,11 @@ optionator@^0.9.3:
type-check "^0.4.0"
word-wrap "^1.2.5"
+os-tmpdir@~1.0.2:
+ version "1.0.2"
+ resolved "https://registry.yarnpkg.com/os-tmpdir/-/os-tmpdir-1.0.2.tgz#bbe67406c79aa85c5cfec766fe5734555dfa1274"
+ integrity sha512-D2FR03Vir7FIu45XBY20mTb+/ZSWB00sjU9jdQXt83gDrI4Ztz5Fs7/yy74g2N5SVQY4xY1qDr4rNddwYRVX0g==
+
p-all@^3.0.0:
version "3.0.0"
resolved "https://registry.yarnpkg.com/p-all/-/p-all-3.0.0.tgz#077c023c37e75e760193badab2bad3ccd5782bfb"
@@ -2939,6 +3240,11 @@ prettier@^3.0.0:
resolved "https://registry.yarnpkg.com/prettier/-/prettier-3.5.3.tgz#4fc2ce0d657e7a02e602549f053b239cb7dfe1b5"
integrity sha512-QQtaxnoDJeAkDvDKWCLiwIXkTgRhwYDEQCghU9Z6q03iyek/rxRh/2lC3HB7P8sWT2xC/y5JDctPLBIGzHKbhw==
+pretty-bytes@^5.6.0:
+ version "5.6.0"
+ resolved "https://registry.yarnpkg.com/pretty-bytes/-/pretty-bytes-5.6.0.tgz#356256f643804773c82f64723fe78c92c62beaeb"
+ integrity sha512-FFw039TmrBqFK8ma/7OL3sDz/VytdtJr044/QUJtH0wK9lb9jLq9tJyIxUwtQJHwar2BqtiA4iCWSwo9JLkzFg==
+
pretty-format@^29.0.0, pretty-format@^29.7.0:
version "29.7.0"
resolved "https://registry.yarnpkg.com/pretty-format/-/pretty-format-29.7.0.tgz#ca42c758310f365bfa71a0bda0a807160b776812"
@@ -3020,6 +3326,11 @@ require-directory@^2.1.1:
resolved "https://registry.yarnpkg.com/require-directory/-/require-directory-2.1.1.tgz#8c64ad5fd30dab1c976e2344ffe7f792a6a6df42"
integrity sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==
+require-from-string@^2.0.2:
+ version "2.0.2"
+ resolved "https://registry.yarnpkg.com/require-from-string/-/require-from-string-2.0.2.tgz#89a7fdd938261267318eafe14f9c32e598c36909"
+ integrity sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==
+
resolve-cwd@^3.0.0:
version "3.0.0"
resolved "https://registry.yarnpkg.com/resolve-cwd/-/resolve-cwd-3.0.0.tgz#0f0075f1bb2544766cf73ba6a6e2adfebcb13f2d"
@@ -3086,7 +3397,7 @@ safe-buffer@5.2.1, safe-buffer@~5.2.0:
resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.2.1.tgz#1eaf9fa9bdb1fdd4ec75f58f9cdb4e6b7827eec6"
integrity sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==
-"safer-buffer@>= 2.1.2 < 3.0.0":
+"safer-buffer@>= 2.1.2 < 3", "safer-buffer@>= 2.1.2 < 3.0.0":
version "2.1.2"
resolved "https://registry.yarnpkg.com/safer-buffer/-/safer-buffer-2.1.2.tgz#44fa161b0187b9549dd84bb91802f9bd8385cd6a"
integrity sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==
@@ -3190,6 +3501,11 @@ signal-exit@^3.0.3, signal-exit@^3.0.7:
resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.7.tgz#a9a1767f8af84155114eaabd73f99273c8f59ad9"
integrity sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==
+signal-exit@^4.1.0:
+ version "4.1.0"
+ resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-4.1.0.tgz#952188c1cbd546070e2dd20d0f41c0ae0530cb04"
+ integrity sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==
+
sisteransi@^1.0.5:
version "1.0.5"
resolved "https://registry.yarnpkg.com/sisteransi/-/sisteransi-1.0.5.tgz#134d681297756437cc05ca01370d3a7a571075ed"
@@ -3334,6 +3650,13 @@ text-table@^0.2.0:
resolved "https://registry.yarnpkg.com/text-table/-/text-table-0.2.0.tgz#7f5ee823ae805207c00af2df4a84ec3fcfa570b4"
integrity sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==
+tmp@^0.0.33:
+ version "0.0.33"
+ resolved "https://registry.yarnpkg.com/tmp/-/tmp-0.0.33.tgz#6d34335889768d21b2bcda0aa277ced3b1bfadf9"
+ integrity sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw==
+ dependencies:
+ os-tmpdir "~1.0.2"
+
tmpl@1.0.5:
version "1.0.5"
resolved "https://registry.yarnpkg.com/tmpl/-/tmpl-1.0.5.tgz#8683e0b902bb9c20c4f726e3c0b69f36518c07cc"
@@ -3474,6 +3797,11 @@ undici-types@~6.21.0:
resolved "https://registry.yarnpkg.com/undici-types/-/undici-types-6.21.0.tgz#691d00af3909be93a7faa13be61b3a5b50ef12cb"
integrity sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==
+universalify@^2.0.0:
+ version "2.0.1"
+ resolved "https://registry.yarnpkg.com/universalify/-/universalify-2.0.1.tgz#168efc2180964e6386d061e094df61afe239b18d"
+ integrity sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw==
+
unpipe@1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/unpipe/-/unpipe-1.0.0.tgz#b2bf4ee8514aae6165b4817829d21b2ef49904ec"
@@ -3537,6 +3865,15 @@ word-wrap@^1.2.5:
resolved "https://registry.yarnpkg.com/word-wrap/-/word-wrap-1.2.5.tgz#d2c45c6dd4fbce621a66f136cbe328afd0410b34"
integrity sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==
+wrap-ansi@^6.2.0:
+ version "6.2.0"
+ resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-6.2.0.tgz#e9393ba07102e6c91a3b221478f0257cd2856e53"
+ integrity sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA==
+ dependencies:
+ ansi-styles "^4.0.0"
+ string-width "^4.1.0"
+ strip-ansi "^6.0.0"
+
wrap-ansi@^7.0.0:
version "7.0.0"
resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-7.0.0.tgz#67e145cff510a6a6984bdf1152911d69d2eb9e43"
@@ -3597,22 +3934,32 @@ yocto-queue@^0.1.0:
resolved "https://registry.yarnpkg.com/yocto-queue/-/yocto-queue-0.1.0.tgz#0294eb3dee05028d31ee1a5fa2c556a6aaf10a1b"
integrity sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==
-zod-to-json-schema@^3.24.1, zod-to-json-schema@^3.24.5:
+yoctocolors-cjs@^2.1.2:
+ version "2.1.3"
+ resolved "https://registry.yarnpkg.com/yoctocolors-cjs/-/yoctocolors-cjs-2.1.3.tgz#7e4964ea8ec422b7a40ac917d3a344cfd2304baa"
+ integrity sha512-U/PBtDf35ff0D8X8D0jfdzHYEPFxAI7jJlxZXwCSez5M3190m+QobIfh+sWDWSHMCWWJN2AWamkegn6vr6YBTw==
+
+zod-to-json-schema@^3.24.5:
version "3.24.5"
resolved "https://registry.yarnpkg.com/zod-to-json-schema/-/zod-to-json-schema-3.24.5.tgz#d1095440b147fb7c2093812a53c54df8d5df50a3"
integrity sha512-/AuWwMP+YqiPbsJx5D6TfgRTc4kTLjsh5SOcd4bLsfUg2RcEXrFMJl1DGgdHy2aCfsIA/cr/1JM0xcB2GZji8g==
+zod-to-json-schema@^3.25.0:
+ version "3.25.0"
+ resolved "https://registry.yarnpkg.com/zod-to-json-schema/-/zod-to-json-schema-3.25.0.tgz#df504c957c4fb0feff467c74d03e6aab0b013e1c"
+ integrity sha512-HvWtU2UG41LALjajJrML6uQejQhNJx+JBO9IflpSja4R03iNWfKXrj6W2h7ljuLyc1nKS+9yDyL/9tD1U/yBnQ==
+
zod-validation-error@^4.0.1:
version "4.0.1"
resolved "https://registry.yarnpkg.com/zod-validation-error/-/zod-validation-error-4.0.1.tgz#a105723eb40299578a6a38cb86647068f6d005b1"
integrity sha512-F3rdaCOHs5ViJ5YTz5zzRtfkQdMdIeKudJAoxy7yB/2ZMEHw73lmCAcQw11r7++20MyGl4WV59EVh7A9rNAyog==
-zod@^3.23.8:
- version "3.24.4"
- resolved "https://registry.yarnpkg.com/zod/-/zod-3.24.4.tgz#e2e2cca5faaa012d76e527d0d36622e0a90c315f"
- integrity sha512-OdqJE9UDRPwWsrHjLN2F8bPxvwJBK22EHLWtanu0LSYr5YqzsaaW3RMgmjwr8Rypg5k+meEJdSPXJZXE/yqOMg==
+"zod@^3.25 || ^4.0":
+ version "4.1.13"
+ resolved "https://registry.yarnpkg.com/zod/-/zod-4.1.13.tgz#93699a8afe937ba96badbb0ce8be6033c0a4b6b1"
+ integrity sha512-AvvthqfqrAhNH9dnfmrfKzX5upOdjUVJYFqNSlkmGf64gRaTzlPwz99IHYnVs28qYAybvAlBV+H7pn0saFY4Ig==
-zod@^3.25.20:
+zod@^3.25.20, zod@^3.25.67:
version "3.25.76"
resolved "https://registry.yarnpkg.com/zod/-/zod-3.25.76.tgz#26841c3f6fd22a6a2760e7ccb719179768471e34"
integrity sha512-gzUt/qt81nXsFGKIFcC3YnfEAx5NkunCfnDlvuBSSFS02bcXu4Lmea0AFIUwbLWxWPx3d9p8S5QoaujKcNQxcQ==
diff --git a/scripts/utils/upload-artifact.sh b/scripts/utils/upload-artifact.sh
index 0870aebc..e169cf10 100755
--- a/scripts/utils/upload-artifact.sh
+++ b/scripts/utils/upload-artifact.sh
@@ -12,9 +12,11 @@ if [[ "$SIGNED_URL" == "null" ]]; then
exit 1
fi
-UPLOAD_RESPONSE=$(tar "${BASE_PATH:+-C$BASE_PATH}" -cz "${ARTIFACT_PATH:-dist}" | curl -v -X PUT \
+TARBALL=$(cd dist && npm pack --silent)
+
+UPLOAD_RESPONSE=$(curl -v -X PUT \
-H "Content-Type: application/gzip" \
- --data-binary @- "$SIGNED_URL" 2>&1)
+ --data-binary "@dist/$TARBALL" "$SIGNED_URL" 2>&1)
if echo "$UPLOAD_RESPONSE" | grep -q "HTTP/[0-9.]* 200"; then
echo -e "\033[32mUploaded build to Stainless storage.\033[0m"
diff --git a/src/client.ts b/src/client.ts
index 1560e2bc..54169b41 100644
--- a/src/client.ts
+++ b/src/client.ts
@@ -189,7 +189,7 @@ export class ImageKit {
baseURL: string;
maxRetries: number;
timeout: number;
- logger: Logger | undefined;
+ logger: Logger;
logLevel: LogLevel | undefined;
fetchOptions: MergedRequestInit | undefined;
@@ -911,10 +911,12 @@ export declare namespace ImageKit {
export type BaseOverlay = API.BaseOverlay;
export type Extensions = API.Extensions;
+ export type GetImageAttributesOptions = API.GetImageAttributesOptions;
export type ImageOverlay = API.ImageOverlay;
export type Overlay = API.Overlay;
export type OverlayPosition = API.OverlayPosition;
export type OverlayTiming = API.OverlayTiming;
+ export type ResponsiveImageAttributes = API.ResponsiveImageAttributes;
export type SolidColorOverlay = API.SolidColorOverlay;
export type SolidColorOverlayTransformation = API.SolidColorOverlayTransformation;
export type SrcOptions = API.SrcOptions;
diff --git a/src/resources/custom-metadata-fields.ts b/src/resources/custom-metadata-fields.ts
index 7629d3f9..81081924 100644
--- a/src/resources/custom-metadata-fields.ts
+++ b/src/resources/custom-metadata-fields.ts
@@ -38,11 +38,7 @@ export class CustomMetadataFields extends APIResource {
* const customMetadataField =
* await client.customMetadataFields.update('id', {
* label: 'price',
- * schema: {
- * type: 'Number',
- * minValue: 1000,
- * maxValue: 3000,
- * },
+ * schema: { minValue: 1000, maxValue: 3000 },
* });
* ```
*/
diff --git a/src/resources/shared.ts b/src/resources/shared.ts
index 6d73d695..9ecb5fcf 100644
--- a/src/resources/shared.ts
+++ b/src/resources/shared.ts
@@ -78,6 +78,54 @@ export namespace Extensions {
}
}
+/**
+ * Options for generating responsive image attributes including `src`, `srcSet`,
+ * and `sizes` for HTML `
` elements. This schema extends `SrcOptions` to add
+ * support for responsive image generation with breakpoints.
+ */
+export interface GetImageAttributesOptions extends SrcOptions {
+ /**
+ * Custom list of **device-width breakpoints** in pixels. These define common
+ * screen widths for responsive image generation.
+ *
+ * Defaults to `[640, 750, 828, 1080, 1200, 1920, 2048, 3840]`. Sorted
+ * automatically.
+ */
+ deviceBreakpoints?: Array;
+
+ /**
+ * Custom list of **image-specific breakpoints** in pixels. Useful for generating
+ * small variants (e.g., placeholders or thumbnails).
+ *
+ * Merged with `deviceBreakpoints` before calculating `srcSet`. Defaults to
+ * `[16, 32, 48, 64, 96, 128, 256, 384]`. Sorted automatically.
+ */
+ imageBreakpoints?: Array;
+
+ /**
+ * The value for the HTML `sizes` attribute (e.g., `"100vw"` or
+ * `"(min-width:768px) 50vw, 100vw"`).
+ *
+ * - If it includes one or more `vw` units, breakpoints smaller than the
+ * corresponding percentage of the smallest device width are excluded.
+ * - If it contains no `vw` units, the full breakpoint list is used.
+ *
+ * Enables a width-based strategy and generates `w` descriptors in `srcSet`.
+ */
+ sizes?: string;
+
+ /**
+ * The intended display width of the image in pixels, used **only when the `sizes`
+ * attribute is not provided**.
+ *
+ * Triggers a DPR-based strategy (1x and 2x variants) and generates `x` descriptors
+ * in `srcSet`.
+ *
+ * Ignored if `sizes` is present.
+ */
+ width?: number;
+}
+
export interface ImageOverlay extends BaseOverlay {
/**
* Specifies the relative path to the image used as an overlay.
@@ -175,6 +223,34 @@ export interface OverlayTiming {
start?: number | string;
}
+/**
+ * Resulting set of attributes suitable for an HTML `
` element. Useful for
+ * enabling responsive image loading with `srcSet` and `sizes`.
+ */
+export interface ResponsiveImageAttributes {
+ /**
+ * URL for the _largest_ candidate (assigned to plain `src`).
+ */
+ src: string;
+
+ /**
+ * `sizes` returned (or synthesised as `100vw`). The value for the HTML `sizes`
+ * attribute.
+ */
+ sizes?: string;
+
+ /**
+ * Candidate set with `w` or `x` descriptors. Multiple image URLs separated by
+ * commas, each with a descriptor.
+ */
+ srcSet?: string;
+
+ /**
+ * Width as a number (if `width` was provided in the input options).
+ */
+ width?: number;
+}
+
export interface SolidColorOverlay extends BaseOverlay {
/**
* Specifies the color of the block using an RGB hex code (e.g., `FF0000`), an RGBA
diff --git a/src/version.ts b/src/version.ts
index 60c81603..ee13ebb3 100644
--- a/src/version.ts
+++ b/src/version.ts
@@ -1 +1 @@
-export const VERSION = '7.1.1'; // x-release-please-version
+export const VERSION = '8.0.0'; // x-release-please-version
diff --git a/yarn.lock b/yarn.lock
index 1935915b..2180b9e6 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -350,45 +350,52 @@
dependencies:
"@cspotcode/source-map-consumer" "0.8.0"
-"@eslint-community/eslint-utils@^4.2.0", "@eslint-community/eslint-utils@^4.4.0":
+"@eslint-community/eslint-utils@^4.4.0":
version "4.4.0"
resolved "https://registry.yarnpkg.com/@eslint-community/eslint-utils/-/eslint-utils-4.4.0.tgz#a23514e8fb9af1269d5f7788aa556798d61c6b59"
integrity sha512-1/sA4dwrzBAyeUoQ6oxahHKmrZvsnLCg4RfxW3ZFGGmQkSNQPFNLV9CUEFQP1x9EYXHTo5p6xdhZM1Ne9p/AfA==
dependencies:
eslint-visitor-keys "^3.3.0"
+"@eslint-community/eslint-utils@^4.8.0":
+ version "4.9.0"
+ resolved "https://registry.yarnpkg.com/@eslint-community/eslint-utils/-/eslint-utils-4.9.0.tgz#7308df158e064f0dd8b8fdb58aa14fa2a7f913b3"
+ integrity sha512-ayVFHdtZ+hsq1t2Dy24wCmGXGe4q9Gu3smhLYALJrr473ZH27MsnSL+LKUlimp4BWJqMDMLmPpx/Q9R3OAlL4g==
+ dependencies:
+ eslint-visitor-keys "^3.4.3"
+
"@eslint-community/regexpp@^4.10.0", "@eslint-community/regexpp@^4.12.1":
version "4.12.1"
resolved "https://registry.yarnpkg.com/@eslint-community/regexpp/-/regexpp-4.12.1.tgz#cfc6cffe39df390a3841cde2abccf92eaa7ae0e0"
integrity sha512-CCZCDJuduB9OUkFkY2IgppNZMi2lBQgD2qzwXkEia16cge2pijY/aXi96CJMquDMn3nJdlPV1A5KrJEXwfLNzQ==
-"@eslint/config-array@^0.19.0":
- version "0.19.2"
- resolved "https://registry.yarnpkg.com/@eslint/config-array/-/config-array-0.19.2.tgz#3060b809e111abfc97adb0bb1172778b90cb46aa"
- integrity sha512-GNKqxfHG2ySmJOBSHg7LxeUx4xpuCoFjacmlCoYWEbaPXLwvfIjixRI12xCQZeULksQb23uiA8F40w5TojpV7w==
+"@eslint/config-array@^0.21.1":
+ version "0.21.1"
+ resolved "https://registry.yarnpkg.com/@eslint/config-array/-/config-array-0.21.1.tgz#7d1b0060fea407f8301e932492ba8c18aff29713"
+ integrity sha512-aw1gNayWpdI/jSYVgzN5pL0cfzU02GT3NBpeT/DXbx1/1x7ZKxFPd9bwrzygx/qiwIQiJ1sw/zD8qY/kRvlGHA==
dependencies:
- "@eslint/object-schema" "^2.1.6"
+ "@eslint/object-schema" "^2.1.7"
debug "^4.3.1"
minimatch "^3.1.2"
-"@eslint/core@^0.10.0":
- version "0.10.0"
- resolved "https://registry.yarnpkg.com/@eslint/core/-/core-0.10.0.tgz#23727063c21b335f752dbb3a16450f6f9cbc9091"
- integrity sha512-gFHJ+xBOo4G3WRlR1e/3G8A6/KZAH6zcE/hkLRCZTi/B9avAG365QhFA8uOGzTMqgTghpn7/fSnscW++dpMSAw==
+"@eslint/config-helpers@^0.4.2":
+ version "0.4.2"
+ resolved "https://registry.yarnpkg.com/@eslint/config-helpers/-/config-helpers-0.4.2.tgz#1bd006ceeb7e2e55b2b773ab318d300e1a66aeda"
+ integrity sha512-gBrxN88gOIf3R7ja5K9slwNayVcZgK6SOUORm2uBzTeIEfeVaIhOpCtTox3P6R7o2jLFwLFTLnC7kU/RGcYEgw==
dependencies:
- "@types/json-schema" "^7.0.15"
+ "@eslint/core" "^0.17.0"
-"@eslint/core@^0.11.0":
- version "0.11.0"
- resolved "https://registry.yarnpkg.com/@eslint/core/-/core-0.11.0.tgz#7a9226e850922e42cbd2ba71361eacbe74352a12"
- integrity sha512-DWUB2pksgNEb6Bz2fggIy1wh6fGgZP4Xyy/Mt0QZPiloKKXerbqq9D3SBQTlCRYOrcRPu4vuz+CGjwdfqxnoWA==
+"@eslint/core@^0.17.0":
+ version "0.17.0"
+ resolved "https://registry.yarnpkg.com/@eslint/core/-/core-0.17.0.tgz#77225820413d9617509da9342190a2019e78761c"
+ integrity sha512-yL/sLrpmtDaFEiUj1osRP4TI2MDz1AddJL+jZ7KSqvBuliN4xqYY54IfdN8qD8Toa6g1iloph1fxQNkjOxrrpQ==
dependencies:
"@types/json-schema" "^7.0.15"
-"@eslint/eslintrc@^3.2.0":
- version "3.2.0"
- resolved "https://registry.yarnpkg.com/@eslint/eslintrc/-/eslintrc-3.2.0.tgz#57470ac4e2e283a6bf76044d63281196e370542c"
- integrity sha512-grOjVNN8P3hjJn/eIETF1wwd12DdnwFDoyceUJLYYdkpbwq3nLi+4fqrTAONx7XDALqlL220wC/RHSC/QTI/0w==
+"@eslint/eslintrc@^3.3.1":
+ version "3.3.3"
+ resolved "https://registry.yarnpkg.com/@eslint/eslintrc/-/eslintrc-3.3.3.tgz#26393a0806501b5e2b6a43aa588a4d8df67880ac"
+ integrity sha512-Kr+LPIUVKz2qkx1HAMH8q1q6azbqBAsXJUxBl/ODDuVPX45Z9DfwB8tPjTi6nNZ8BuM3nbJxC5zCAg5elnBUTQ==
dependencies:
ajv "^6.12.4"
debug "^4.3.2"
@@ -396,26 +403,26 @@
globals "^14.0.0"
ignore "^5.2.0"
import-fresh "^3.2.1"
- js-yaml "^4.1.0"
+ js-yaml "^4.1.1"
minimatch "^3.1.2"
strip-json-comments "^3.1.1"
-"@eslint/js@9.20.0":
- version "9.20.0"
- resolved "https://registry.yarnpkg.com/@eslint/js/-/js-9.20.0.tgz#7421bcbe74889fcd65d1be59f00130c289856eb4"
- integrity sha512-iZA07H9io9Wn836aVTytRaNqh00Sad+EamwOVJT12GTLw1VGMFV/4JaME+JjLtr9fiGaoWgYnS54wrfWsSs4oQ==
+"@eslint/js@9.39.1":
+ version "9.39.1"
+ resolved "https://registry.yarnpkg.com/@eslint/js/-/js-9.39.1.tgz#0dd59c3a9f40e3f1882975c321470969243e0164"
+ integrity sha512-S26Stp4zCy88tH94QbBv3XCuzRQiZ9yXofEILmglYTh/Ug/a9/umqvgFtYBAo3Lp0nsI/5/qH1CCrbdK3AP1Tw==
-"@eslint/object-schema@^2.1.6":
- version "2.1.6"
- resolved "https://registry.yarnpkg.com/@eslint/object-schema/-/object-schema-2.1.6.tgz#58369ab5b5b3ca117880c0f6c0b0f32f6950f24f"
- integrity sha512-RBMg5FRL0I0gs51M/guSAj5/e14VQ4tpZnQNWwuDT66P14I43ItmPfIZRhO9fUVIPOAQXU47atlywZ/czoqFPA==
+"@eslint/object-schema@^2.1.7":
+ version "2.1.7"
+ resolved "https://registry.yarnpkg.com/@eslint/object-schema/-/object-schema-2.1.7.tgz#6e2126a1347e86a4dedf8706ec67ff8e107ebbad"
+ integrity sha512-VtAOaymWVfZcmZbp6E2mympDIHvyjXs/12LqWYjVw6qjrfF+VK+fyG33kChz3nnK+SU5/NeHOqrTEHS8sXO3OA==
-"@eslint/plugin-kit@^0.2.5":
- version "0.2.5"
- resolved "https://registry.yarnpkg.com/@eslint/plugin-kit/-/plugin-kit-0.2.5.tgz#ee07372035539e7847ef834e3f5e7b79f09e3a81"
- integrity sha512-lB05FkqEdUg2AA0xEbUz0SnkXT1LcCTa438W4IWTUh4hdOnVbQyOJ81OrDXsJk/LSiJHubgGEFoR5EHq1NsH1A==
+"@eslint/plugin-kit@^0.4.1":
+ version "0.4.1"
+ resolved "https://registry.yarnpkg.com/@eslint/plugin-kit/-/plugin-kit-0.4.1.tgz#9779e3fd9b7ee33571a57435cf4335a1794a6cb2"
+ integrity sha512-43/qtrDUokr7LJqoF2c3+RInu/t4zfrpYdoSDfYyhg52rwLV6TnOvdG4fXm7IkSB3wErkcmJS9iEhjVtOSEjjA==
dependencies:
- "@eslint/core" "^0.10.0"
+ "@eslint/core" "^0.17.0"
levn "^0.4.1"
"@humanfs/core@^0.19.1":
@@ -441,10 +448,10 @@
resolved "https://registry.yarnpkg.com/@humanwhocodes/retry/-/retry-0.3.1.tgz#c72a5c76a9fbaf3488e231b13dc52c0da7bab42a"
integrity sha512-JBxkERygn7Bv/GbN5Rv8Ul6LVknS+5Bp6RgDC/O8gEBU/yeH5Ui5C/OlWrTb6qct7LjjfT6Re2NxB0ln0yYybA==
-"@humanwhocodes/retry@^0.4.1":
- version "0.4.1"
- resolved "https://registry.yarnpkg.com/@humanwhocodes/retry/-/retry-0.4.1.tgz#9a96ce501bc62df46c4031fbd970e3cc6b10f07b"
- integrity sha512-c7hNEllBlenFTHBky65mhq8WD2kbN9Q6gk0bTk8lSBvc554jpXSkST1iePudpt7+A/AQvuHs9EMqjHDXMY1lrA==
+"@humanwhocodes/retry@^0.4.2":
+ version "0.4.3"
+ resolved "https://registry.yarnpkg.com/@humanwhocodes/retry/-/retry-0.4.3.tgz#c2b9d2e374ee62c586d3adbea87199b1d7a7a6ba"
+ integrity sha512-bV0Tgo9K4hfPCek+aMAn81RppFKv2ySDQeMoSZuvTASywNTnVJCArCZE2FWqpvIatKu7VMRLWlR1EazvVhDyhQ==
"@istanbuljs/load-nyc-config@^1.0.0":
version "1.1.0"
@@ -1062,6 +1069,11 @@ acorn@^8.14.0:
resolved "https://registry.yarnpkg.com/acorn/-/acorn-8.14.0.tgz#063e2c70cac5fb4f6467f0b11152e04c682795b0"
integrity sha512-cl669nCJTZBsL97OF4kUQm5g5hC2uihk0NxY3WENAC0TYdILVkAyHymAntgxGkl7K+t0cXIrH5siy5S4XkFycA==
+acorn@^8.15.0:
+ version "8.15.0"
+ resolved "https://registry.yarnpkg.com/acorn/-/acorn-8.15.0.tgz#a360898bc415edaac46c8241f6383975b930b816"
+ integrity sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==
+
acorn@^8.4.1:
version "8.7.0"
resolved "https://registry.yarnpkg.com/acorn/-/acorn-8.7.0.tgz#90951fde0f8f09df93549481e5fc141445b791cf"
@@ -1565,15 +1577,15 @@ eslint-plugin-unused-imports@^4.1.4:
resolved "https://registry.yarnpkg.com/eslint-plugin-unused-imports/-/eslint-plugin-unused-imports-4.1.4.tgz#62ddc7446ccbf9aa7b6f1f0b00a980423cda2738"
integrity sha512-YptD6IzQjDardkl0POxnnRBhU1OEePMV0nd6siHaRBbd+lyh6NAhFEobiznKU7kTsSsDeSD62Pe7kAM1b7dAZQ==
-eslint-scope@^8.2.0:
- version "8.2.0"
- resolved "https://registry.yarnpkg.com/eslint-scope/-/eslint-scope-8.2.0.tgz#377aa6f1cb5dc7592cfd0b7f892fd0cf352ce442"
- integrity sha512-PHlWUfG6lvPc3yvP5A4PNyBL1W8fkDUccmI21JUu/+GKZBoH/W5u6usENXUrWFRsyoW5ACUjFGgAFQp5gUlb/A==
+eslint-scope@^8.4.0:
+ version "8.4.0"
+ resolved "https://registry.yarnpkg.com/eslint-scope/-/eslint-scope-8.4.0.tgz#88e646a207fad61436ffa39eb505147200655c82"
+ integrity sha512-sNXOfKCn74rt8RICKMvJS7XKV/Xk9kA7DyJr8mJik3S7Cwgy3qlkkmyS2uQB3jiJg6VNdZd/pDBJu0nvG2NlTg==
dependencies:
esrecurse "^4.3.0"
estraverse "^5.2.0"
-eslint-visitor-keys@^3.3.0:
+eslint-visitor-keys@^3.3.0, eslint-visitor-keys@^3.4.3:
version "3.4.3"
resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz#0cd72fe8550e3c2eae156a96a4dddcd1c8ac5800"
integrity sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==
@@ -1583,31 +1595,36 @@ eslint-visitor-keys@^4.2.0:
resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-4.2.0.tgz#687bacb2af884fcdda8a6e7d65c606f46a14cd45"
integrity sha512-UyLnSehNt62FFhSwjZlHmeokpRK59rcz29j+F1/aDgbkbRTk7wIc9XzdoasMUbRNKDM0qQt/+BJ4BrpFeABemw==
-eslint@^9.20.1:
- version "9.20.1"
- resolved "https://registry.yarnpkg.com/eslint/-/eslint-9.20.1.tgz#923924c078f5226832449bac86662dd7e53c91d6"
- integrity sha512-m1mM33o6dBUjxl2qb6wv6nGNwCAsns1eKtaQ4l/NPHeTvhiUPbtdfMyktxN4B3fgHIgsYh1VT3V9txblpQHq+g==
+eslint-visitor-keys@^4.2.1:
+ version "4.2.1"
+ resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-4.2.1.tgz#4cfea60fe7dd0ad8e816e1ed026c1d5251b512c1"
+ integrity sha512-Uhdk5sfqcee/9H/rCOJikYz67o0a2Tw2hGRPOG2Y1R2dg7brRe1uG0yaNQDHu+TO/uQPF/5eCapvYSmHUjt7JQ==
+
+eslint@^9.39.1:
+ version "9.39.1"
+ resolved "https://registry.yarnpkg.com/eslint/-/eslint-9.39.1.tgz#be8bf7c6de77dcc4252b5a8dcb31c2efff74a6e5"
+ integrity sha512-BhHmn2yNOFA9H9JmmIVKJmd288g9hrVRDkdoIgRCRuSySRUHH7r/DI6aAXW9T1WwUuY3DFgrcaqB+deURBLR5g==
dependencies:
- "@eslint-community/eslint-utils" "^4.2.0"
+ "@eslint-community/eslint-utils" "^4.8.0"
"@eslint-community/regexpp" "^4.12.1"
- "@eslint/config-array" "^0.19.0"
- "@eslint/core" "^0.11.0"
- "@eslint/eslintrc" "^3.2.0"
- "@eslint/js" "9.20.0"
- "@eslint/plugin-kit" "^0.2.5"
+ "@eslint/config-array" "^0.21.1"
+ "@eslint/config-helpers" "^0.4.2"
+ "@eslint/core" "^0.17.0"
+ "@eslint/eslintrc" "^3.3.1"
+ "@eslint/js" "9.39.1"
+ "@eslint/plugin-kit" "^0.4.1"
"@humanfs/node" "^0.16.6"
"@humanwhocodes/module-importer" "^1.0.1"
- "@humanwhocodes/retry" "^0.4.1"
+ "@humanwhocodes/retry" "^0.4.2"
"@types/estree" "^1.0.6"
- "@types/json-schema" "^7.0.15"
ajv "^6.12.4"
chalk "^4.0.0"
cross-spawn "^7.0.6"
debug "^4.3.2"
escape-string-regexp "^4.0.0"
- eslint-scope "^8.2.0"
- eslint-visitor-keys "^4.2.0"
- espree "^10.3.0"
+ eslint-scope "^8.4.0"
+ eslint-visitor-keys "^4.2.1"
+ espree "^10.4.0"
esquery "^1.5.0"
esutils "^2.0.2"
fast-deep-equal "^3.1.3"
@@ -1623,7 +1640,7 @@ eslint@^9.20.1:
natural-compare "^1.4.0"
optionator "^0.9.3"
-espree@^10.0.1, espree@^10.3.0:
+espree@^10.0.1:
version "10.3.0"
resolved "https://registry.yarnpkg.com/espree/-/espree-10.3.0.tgz#29267cf5b0cb98735b65e64ba07e0ed49d1eed8a"
integrity sha512-0QYC8b24HWY8zjRnDTL6RiHfDbAWn63qb4LMj1Z4b076A4une81+z03Kg7l7mn/48PUTqoLptSXez8oknU8Clg==
@@ -1632,6 +1649,15 @@ espree@^10.0.1, espree@^10.3.0:
acorn-jsx "^5.3.2"
eslint-visitor-keys "^4.2.0"
+espree@^10.4.0:
+ version "10.4.0"
+ resolved "https://registry.yarnpkg.com/espree/-/espree-10.4.0.tgz#d54f4949d4629005a1fa168d937c3ff1f7e2a837"
+ integrity sha512-j6PAQ2uUr79PZhBjP5C5fhl8e39FmRnOjsD5lGnWrFU8i2G776tBK7+nP8KuQUTTyAZUwfQqXAgrVH5MbH9CYQ==
+ dependencies:
+ acorn "^8.15.0"
+ acorn-jsx "^5.3.2"
+ eslint-visitor-keys "^4.2.1"
+
esprima@^4.0.0:
version "4.0.1"
resolved "https://registry.yarnpkg.com/esprima/-/esprima-4.0.1.tgz#13b04cdb3e6c5d19df91ab6987a8695619b0aa71"
@@ -2450,10 +2476,10 @@ js-yaml@^3.13.1:
argparse "^1.0.7"
esprima "^4.0.0"
-js-yaml@^4.1.0:
- version "4.1.0"
- resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-4.1.0.tgz#c1fb65f8f5017901cdd2c951864ba18458a10602"
- integrity sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==
+js-yaml@^4.1.1:
+ version "4.1.1"
+ resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-4.1.1.tgz#854c292467705b699476e1a2decc0c8a3458806b"
+ integrity sha512-qQKT4zQxXl8lLwBtHMWwaTcGfFOZviOJet3Oy/xmGk2gZH677CJM9EvtfdSkgWcATZhj/55JZ0rmy3myCT5lsA==
dependencies:
argparse "^2.0.1"