Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
16 commits
Select commit Hold shift + click to select a range
c08f7c0
fix(client): avoid memory leak with abort signals
stainless-app[bot] Feb 2, 2026
4b5fcbf
chore(client): do not parse responses with empty content-length
stainless-app[bot] Feb 2, 2026
5f6c688
chore(internal): support oauth authorization code flow for MCP servers
stainless-app[bot] Feb 3, 2026
46c04e1
chore(client): restructure abort controller binding
stainless-app[bot] Feb 4, 2026
ff4b97e
chore(internal): refactor flag parsing for MCP servers and add debug …
stainless-app[bot] Feb 4, 2026
cdce131
feat(mcp): add initial server instructions
stainless-app[bot] Feb 4, 2026
0738e88
fix(client): avoid removing abort listener too early
stainless-app[bot] Feb 5, 2026
83d1174
chore(internal): add health check to MCP server when running in HTTP …
stainless-app[bot] Feb 6, 2026
61a5d88
chore(internal): upgrade hono
stainless-app[bot] Feb 6, 2026
90eae18
chore(internal): always generate MCP server dockerfiles and upgrade a…
stainless-app[bot] Feb 9, 2026
4a86182
chore(internal): allow basic filtering of methods allowed for MCP cod…
stainless-app[bot] Feb 9, 2026
7cd3980
chore(internal): avoid type checking errors with ts-reset
stainless-app[bot] Feb 11, 2026
bf91d73
chore(mcp): forward STAINLESS_API_KEY to docs search endpoint
stainless-app[bot] Feb 13, 2026
b2e0a75
chore(internal): improve layout of generated MCP server files
stainless-app[bot] Feb 13, 2026
d96f483
chore(internal/client): fix form-urlencoded requests
stainless-app[bot] Feb 17, 2026
d7230a4
release: 7.4.0
stainless-app[bot] Feb 17, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
59 changes: 59 additions & 0 deletions .dockerignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
# Dependencies
node_modules/
**/node_modules/

# Build outputs
dist/
**/dist/

# Git
.git/
.gitignore

# CI/CD
.github/
.gitlab-ci.yml
.travis.yml

# IDE
.vscode/
.idea/
*.swp
*.swo
*~

# OS
.DS_Store
Thumbs.db

# Testing
test/
tests/
__tests__/
*.test.js
*.spec.js
coverage/
.nyc_output/

# Logs
*.log
npm-debug.log*
yarn-debug.log*
yarn-error.log*

# Environment
.env
.env.*

# Temporary files
*.tmp
*.temp
.cache/

# Examples and scripts
examples/
bin/

# Other packages (we only need mcp-server)
packages/*/
!packages/mcp-server/
2 changes: 1 addition & 1 deletion .release-please-manifest.json
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
{
".": "7.3.0"
".": "7.4.0"
}
30 changes: 30 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,35 @@
# Changelog

## 7.4.0 (2026-02-17)

Full Changelog: [v7.3.0...v7.4.0](https://github.com/imagekit-developer/imagekit-nodejs/compare/v7.3.0...v7.4.0)

### Features

* **mcp:** add initial server instructions ([cdce131](https://github.com/imagekit-developer/imagekit-nodejs/commit/cdce131dc17fba5469393a285ac536acd74742b2))


### Bug Fixes

* **client:** avoid memory leak with abort signals ([c08f7c0](https://github.com/imagekit-developer/imagekit-nodejs/commit/c08f7c04267e000d51cfad22ec8337e456d20171))
* **client:** avoid removing abort listener too early ([0738e88](https://github.com/imagekit-developer/imagekit-nodejs/commit/0738e8884a59ddac579fab6a65e0221fdff4247c))


### Chores

* **client:** do not parse responses with empty content-length ([4b5fcbf](https://github.com/imagekit-developer/imagekit-nodejs/commit/4b5fcbfd1188573ccd1cea40b8e4924a5e2051dc))
* **client:** restructure abort controller binding ([46c04e1](https://github.com/imagekit-developer/imagekit-nodejs/commit/46c04e16c46bca7bc1b0383d151f027d7d918611))
* **internal/client:** fix form-urlencoded requests ([d96f483](https://github.com/imagekit-developer/imagekit-nodejs/commit/d96f4832db9e8c16cbeae32f9a7eb46234bb64ed))
* **internal:** add health check to MCP server when running in HTTP mode ([83d1174](https://github.com/imagekit-developer/imagekit-nodejs/commit/83d1174751241a66748b9d0f4b2b92f37715d4ad))
* **internal:** allow basic filtering of methods allowed for MCP code mode ([4a86182](https://github.com/imagekit-developer/imagekit-nodejs/commit/4a861827d463d2b6e9812a4aa58d2df14cb356bf))
* **internal:** always generate MCP server dockerfiles and upgrade associated dependencies ([90eae18](https://github.com/imagekit-developer/imagekit-nodejs/commit/90eae18e29708d7596a6e783cad196c9a4f75f39))
* **internal:** avoid type checking errors with ts-reset ([7cd3980](https://github.com/imagekit-developer/imagekit-nodejs/commit/7cd398067ad0736b67bfb3d8ace58d15a94c1fd2))
* **internal:** improve layout of generated MCP server files ([b2e0a75](https://github.com/imagekit-developer/imagekit-nodejs/commit/b2e0a75d79757596569d0277467ccad531d49bdd))
* **internal:** refactor flag parsing for MCP servers and add debug flag ([ff4b97e](https://github.com/imagekit-developer/imagekit-nodejs/commit/ff4b97e40fb46ca0b4f3229074c3f614b045641c))
* **internal:** support oauth authorization code flow for MCP servers ([5f6c688](https://github.com/imagekit-developer/imagekit-nodejs/commit/5f6c688f4f41df60d88fce94bc10cfdce4e29d78))
* **internal:** upgrade hono ([61a5d88](https://github.com/imagekit-developer/imagekit-nodejs/commit/61a5d8863e4fcb692d187bb0a7b44e1788faf8ee))
* **mcp:** forward STAINLESS_API_KEY to docs search endpoint ([bf91d73](https://github.com/imagekit-developer/imagekit-nodejs/commit/bf91d7300f134a716038b00bbdcf0cd5932176ea))

## 7.3.0 (2026-02-02)

Full Changelog: [v7.2.2...v7.3.0](https://github.com/imagekit-developer/imagekit-nodejs/compare/v7.2.2...v7.3.0)
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@imagekit/nodejs",
"version": "7.3.0",
"version": "7.4.0",
"description": "Offical NodeJS SDK for ImageKit.io integration",
"author": "Image Kit <developer@imagekit.io>",
"types": "dist/index.d.ts",
Expand Down
71 changes: 71 additions & 0 deletions packages/mcp-server/Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
# Dockerfile for Image Kit MCP Server
#
# This Dockerfile builds a Docker image for the MCP Server.
#
# To build the image locally:
# docker build -f packages/mcp-server/Dockerfile -t @imagekit/api-mcp:local .
#
# To run the image:
# docker run -i @imagekit/api-mcp:local [OPTIONS]
#
# Common options:
# --tool=<name> Include specific tools
# --resource=<name> Include tools for specific resources
# --operation=read|write Filter by operation type
# --client=<type> Set client compatibility (e.g., claude, cursor)
# --transport=<type> Set transport type (stdio or http)
#
# For a full list of options:
# docker run -i @imagekit/api-mcp:local --help
#
# Note: The MCP server uses stdio transport by default. Docker's -i flag
# enables interactive mode, allowing the container to communicate over stdin/stdout.

# Build stage
FROM node:24-alpine AS builder

# Install bash for build script
RUN apk add --no-cache bash openssl

# Set working directory
WORKDIR /build

# Copy entire repository
COPY . .

# Install all dependencies and build everything
RUN yarn install --frozen-lockfile && \
yarn build

# Production stage
FROM node:24-alpine

# Add non-root user
RUN addgroup -g 1001 -S nodejs && adduser -S nodejs -u 1001

# Set working directory
WORKDIR /app

# Copy the built mcp-server dist directory
COPY --from=builder /build/packages/mcp-server/dist ./

# Copy node_modules from mcp-server (includes all production deps)
COPY --from=builder /build/packages/mcp-server/node_modules ./node_modules

# Copy the built @imagekit/nodejs into node_modules
COPY --from=builder /build/dist ./node_modules/@imagekit/nodejs

# Change ownership to nodejs user
RUN chown -R nodejs:nodejs /app

# Switch to non-root user
USER nodejs

# The MCP server uses stdio transport by default
# No exposed ports needed for stdio communication

# Set the entrypoint to the MCP server
ENTRYPOINT ["node", "index.js"]

# Allow passing arguments to the MCP server
CMD []
2 changes: 1 addition & 1 deletion packages/mcp-server/cloudflare-worker/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@
"@cloudflare/workers-oauth-provider": "^0.0.5",
"@modelcontextprotocol/sdk": "^1.25.2",
"agents": "^0.0.88",
"hono": "^4.11.4",
"hono": "^4.11.7",
"@imagekit/api-mcp": "latest",
"zod": "^3.24.4"
}
Expand Down
7 changes: 6 additions & 1 deletion packages/mcp-server/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@imagekit/api-mcp",
"version": "7.3.0",
"version": "7.4.0",
"description": "The official MCP Server for the Image Kit API",
"author": "Image Kit <developer@imagekit.io>",
"types": "dist/index.d.ts",
Expand Down Expand Up @@ -34,10 +34,13 @@
"@cloudflare/cabidela": "^0.2.4",
"@modelcontextprotocol/sdk": "^1.25.2",
"@valtown/deno-http-worker": "^0.0.21",
"cookie-parser": "^1.4.6",
"cors": "^2.8.5",
"express": "^5.1.0",
"fuse.js": "^7.1.0",
"jq-web": "https://github.com/stainless-api/jq-web/releases/download/v0.8.8/jq-web.tar.gz",
"morgan": "^1.10.0",
"morgan-body": "^2.6.9",
"qs": "^6.14.1",
"typescript": "5.8.3",
"yargs": "^17.7.2",
Expand All @@ -50,9 +53,11 @@
},
"devDependencies": {
"@anthropic-ai/mcpb": "^2.1.2",
"@types/cookie-parser": "^1.4.10",
"@types/cors": "^2.8.19",
"@types/express": "^5.0.3",
"@types/jest": "^29.4.0",
"@types/morgan": "^1.9.10",
"@types/qs": "^6.14.0",
"@types/yargs": "^17.0.8",
"@typescript-eslint/eslint-plugin": "8.31.1",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
import { IncomingMessage } from 'node:http';
import { ClientOptions } from '@imagekit/nodejs';

export const parseAuthHeaders = (req: IncomingMessage): Partial<ClientOptions> => {
export const parseAuthHeaders = (req: IncomingMessage, required?: boolean): Partial<ClientOptions> => {
if (req.headers.authorization) {
const scheme = req.headers.authorization.split(' ')[0]!;
const value = req.headers.authorization.slice(scheme.length + 1);
Expand All @@ -19,6 +19,8 @@ export const parseAuthHeaders = (req: IncomingMessage): Partial<ClientOptions> =
'Unsupported authorization scheme. Expected the "Authorization" header to be a supported scheme (Basic).',
);
}
} else if (required) {
throw new Error('Missing required Authorization header; see WWW-Authenticate header for details.');
}

const privateKey =
Expand Down
23 changes: 21 additions & 2 deletions packages/mcp-server/src/code-tool.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,9 @@

import { McpTool, Metadata, ToolCallResult, asErrorResult, asTextContentResult } from './types';
import { Tool } from '@modelcontextprotocol/sdk/types.js';
import { readEnv, requireValue } from './server';
import { readEnv, requireValue } from './util';
import { WorkerInput, WorkerOutput } from './code-tool-types';
import { SdkMethod } from './methods';
import { ImageKit } from '@imagekit/nodejs';

const prompt = `Runs JavaScript code to interact with the Image Kit API.
Expand Down Expand Up @@ -35,7 +36,7 @@ Variables will not persist between calls, so make sure to return or log any data
*
* @param endpoints - The endpoints to include in the list.
*/
export function codeTool(): McpTool {
export function codeTool(params: { blockedMethods: SdkMethod[] | undefined }): McpTool {
const metadata: Metadata = { resource: 'all', operation: 'write', tags: [] };
const tool: Tool = {
name: 'execute',
Expand All @@ -59,6 +60,24 @@ export function codeTool(): McpTool {
const code = args.code as string;
const intent = args.intent as string | undefined;

// Do very basic blocking of code that includes forbidden method names.
//
// WARNING: This is not secure against obfuscation and other evasion methods. If
// stronger security blocks are required, then these should be enforced in the downstream
// API (e.g., by having users call the MCP server with API keys with limited permissions).
if (params.blockedMethods) {
const blockedMatches = params.blockedMethods.filter((method) =>
code.includes(method.fullyQualifiedName),
);
if (blockedMatches.length > 0) {
return asErrorResult(
`The following methods have been blocked by the MCP server and cannot be used in code execution: ${blockedMatches
.map((m) => m.fullyQualifiedName)
.join(', ')}`,
);
}
}

// 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');
Expand Down
8 changes: 7 additions & 1 deletion packages/mcp-server/src/docs-search-tool.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.

import { Metadata, asTextContentResult } from './types';
import { readEnv } from './util';

import { Tool } from '@modelcontextprotocol/sdk/types.js';

Expand Down Expand Up @@ -45,7 +46,12 @@ const docsSearchURL =
export const handler = async (_: unknown, args: Record<string, unknown> | undefined) => {
const body = args as any;
const query = new URLSearchParams(body).toString();
const result = await fetch(`${docsSearchURL}?${query}`);
const stainlessAPIKey = readEnv('STAINLESS_API_KEY');
const result = await fetch(`${docsSearchURL}?${query}`, {
headers: {
...(stainlessAPIKey && { Authorization: stainlessAPIKey }),
},
});

if (!result.ok) {
throw new Error(
Expand Down
Loading