diff --git a/.changeset/mcp-client-header.md b/.changeset/mcp-client-header.md new file mode 100644 index 00000000..2d53e499 --- /dev/null +++ b/.changeset/mcp-client-header.md @@ -0,0 +1,6 @@ +--- +"@transloadit/node": patch +"@transloadit/mcp-server": patch +--- + +Allow overriding the Transloadit-Client header and set MCP server requests to its own client name. diff --git a/.changeset/mcp-client-suffix.md b/.changeset/mcp-client-suffix.md new file mode 100644 index 00000000..8bb3fc9c --- /dev/null +++ b/.changeset/mcp-client-suffix.md @@ -0,0 +1,5 @@ +--- +"@transloadit/mcp-server": patch +--- + +Allow appending a client header suffix via TRANSLOADIT_CLIENT_SUFFIX. diff --git a/docs/fingerprint/transloadit-baseline.json b/docs/fingerprint/transloadit-baseline.json index 5264468e..38f5bda9 100644 --- a/docs/fingerprint/transloadit-baseline.json +++ b/docs/fingerprint/transloadit-baseline.json @@ -1,13 +1,13 @@ { "packageDir": "/home/kvz/code/node-sdk/packages/transloadit", "tarball": { - "filename": "transloadit-4.4.0.tgz", - "sizeBytes": 1231819, - "sha256": "102ba99495314297dd66ad979eb74831eac5976b0db8a5a6a987352f435be9cf" + "filename": "transloadit-4.5.0.tgz", + "sizeBytes": 1231897, + "sha256": "25973b1871ef9e7b7a20a8baeafc5fc886e7f3c75e8e4b75173d1e49ef517e7c" }, "packageJson": { "name": "transloadit", - "version": "4.4.0", + "version": "4.5.0", "main": "./dist/Transloadit.js", "exports": { ".": "./dist/Transloadit.js", @@ -578,8 +578,8 @@ }, { "path": "dist/Transloadit.js", - "sizeBytes": 36958, - "sha256": "2e5576936e50d9a82f881523ce5412849fd37b5822af7f45161cf125f6f0b6f8" + "sizeBytes": 37047, + "sha256": "52307d87e842595809ab147b293f16ec19ecc0df6ac15dc84ed77cc5021e8a6e" }, { "path": "dist/alphalib/tryCatch.js", @@ -679,7 +679,7 @@ { "path": "package.json", "sizeBytes": 2391, - "sha256": "5962c802e97833315e93a7c52bfca389553e5b75a407c96311ea53070a63f633" + "sha256": "4af2586ca811425205596d6466c37edb07fb7800f8cbe0813b9bb738a59f6ffd" }, { "path": "dist/alphalib/types/robots/_index.d.ts.map", @@ -1793,13 +1793,13 @@ }, { "path": "dist/Transloadit.d.ts.map", - "sizeBytes": 6408, - "sha256": "a9b98cae57c602c418ae9dfc5cfa58fd77939f08405025f57f699275c30a8a24" + "sizeBytes": 6465, + "sha256": "52e2e1a4a3d0e72d6776e2451daee9ef29ed5dd71462b7684f7dc913411f5d38" }, { "path": "dist/Transloadit.js.map", - "sizeBytes": 26961, - "sha256": "320415c206db61d9671db650be09d4b1660595b9bd62d3de1d00fb3a24c4be89" + "sizeBytes": 27058, + "sha256": "fe0e2aa2301e196b6681a3298f6270a1c5a8f70134f8d43ab3c1d8d27a7c3253" }, { "path": "dist/alphalib/tryCatch.d.ts.map", @@ -3113,13 +3113,13 @@ }, { "path": "dist/Transloadit.d.ts", - "sizeBytes": 11857, - "sha256": "e9aaa44ff7d26d3e78164e8205973ce71711579ca4a73644a6e66c8c7aa7baae" + "sizeBytes": 11907, + "sha256": "8680bb93b17c3e41157ed811dc82551687b8bd6e9ea9df67a19f183dfe5a8c94" }, { "path": "src/Transloadit.ts", - "sizeBytes": 41508, - "sha256": "5488003aefec2aa534a2b00bda60dbb287f02987bbb399e92ab63f913a267679" + "sizeBytes": 41628, + "sha256": "d4a72707042c784d606c7f347711ad4f50b730700b4789b0fc385de85ade5dd3" }, { "path": "dist/alphalib/tryCatch.d.ts", diff --git a/docs/fingerprint/transloadit-baseline.package.json b/docs/fingerprint/transloadit-baseline.package.json index a3d64f93..4bc104d8 100644 --- a/docs/fingerprint/transloadit-baseline.package.json +++ b/docs/fingerprint/transloadit-baseline.package.json @@ -1,6 +1,6 @@ { "name": "transloadit", - "version": "4.4.0", + "version": "4.5.0", "description": "Node.js SDK for Transloadit", "type": "module", "keywords": [ diff --git a/packages/mcp-server/src/cli.ts b/packages/mcp-server/src/cli.ts index 7fbdcb9e..206c537b 100644 --- a/packages/mcp-server/src/cli.ts +++ b/packages/mcp-server/src/cli.ts @@ -126,6 +126,7 @@ const main = async (): Promise => { const mcpToken = (fileConfig.mcpToken ?? process.env.TRANSLOADIT_MCP_TOKEN) as | string | undefined + const clientSuffix = process.env.TRANSLOADIT_CLIENT_SUFFIX as string | undefined if (!isLocalHost(host) && !mcpToken) { throw new Error('TRANSLOADIT_MCP_TOKEN is required when binding to non-localhost host.') @@ -135,6 +136,7 @@ const main = async (): Promise => { authKey: (fileConfig.authKey ?? process.env.TRANSLOADIT_KEY) as string | undefined, authSecret: (fileConfig.authSecret ?? process.env.TRANSLOADIT_SECRET) as string | undefined, endpoint, + clientSuffix, mcpToken, allowedOrigins: fileConfig.allowedOrigins as string[] | undefined, allowedHosts: fileConfig.allowedHosts as string[] | undefined, @@ -170,6 +172,7 @@ const main = async (): Promise => { authKey: process.env.TRANSLOADIT_KEY, authSecret: process.env.TRANSLOADIT_SECRET, endpoint: process.env.TRANSLOADIT_ENDPOINT, + clientSuffix: process.env.TRANSLOADIT_CLIENT_SUFFIX, }) const transport = new StdioServerTransport() await server.connect(transport) diff --git a/packages/mcp-server/src/server.ts b/packages/mcp-server/src/server.ts index c50bd8ad..6576e6df 100644 --- a/packages/mcp-server/src/server.ts +++ b/packages/mcp-server/src/server.ts @@ -24,6 +24,8 @@ export type TransloaditMcpServerOptions = { endpoint?: string serverName?: string serverVersion?: string + clientName?: string + clientSuffix?: string } type LintIssueOutput = { @@ -278,11 +280,21 @@ const buildToolError = ( ], }) +const getClientName = (options: TransloaditMcpServerOptions): string => { + const base = options.clientName ?? `mcp-server:${packageJson.version}` + const suffix = options.clientSuffix + if (suffix && suffix.trim() !== '') { + return `${base}${suffix}` + } + return base +} + const createLintClient = (options: TransloaditMcpServerOptions): Transloadit => new Transloadit({ authKey: options.authKey ?? 'mcp', authSecret: options.authSecret ?? 'mcp', endpoint: options.endpoint, + clientName: getClientName(options), }) const getHeaderValue = (headers: HeaderMap | undefined, name: string): string | undefined => { @@ -315,6 +327,7 @@ const createLiveClient = ( authKey: options.authKey, authSecret: options.authSecret, endpoint: options.endpoint, + clientName: getClientName(options), }), } } @@ -333,6 +346,7 @@ const createLiveClient = ( authKey: options.authKey, authSecret: options.authSecret, endpoint: options.endpoint, + clientName: getClientName(options), }), } } diff --git a/packages/node/src/Transloadit.ts b/packages/node/src/Transloadit.ts index 60d8c385..14c5dbd0 100644 --- a/packages/node/src/Transloadit.ts +++ b/packages/node/src/Transloadit.ts @@ -322,6 +322,7 @@ type BaseOptions = { timeout?: number gotRetry?: Partial validateResponses?: boolean + clientName?: string } export type Options = BaseOptions & (AuthKeySecret | AuthToken) @@ -341,6 +342,8 @@ export class Transloadit { private _gotRetry: Partial + private _clientName: string + private _lastUsedAssemblyUrl = '' private _validateResponses = false @@ -369,6 +372,7 @@ export class Transloadit { this._endpoint = opts.endpoint || 'https://api2.transloadit.com' this._maxRetries = opts.maxRetries != null ? opts.maxRetries : 5 this._defaultTimeout = opts.timeout != null ? opts.timeout : 60000 + this._clientName = opts.clientName?.trim() || `node-sdk:${version}` // Passed on to got https://github.com/sindresorhus/got/blob/main/documentation/7-retry.md this._gotRetry = opts.gotRetry != null ? opts.gotRetry : { limit: 0 } @@ -1258,7 +1262,7 @@ export class Transloadit { body: form, timeout, headers: { - 'Transloadit-Client': `node-sdk:${version}`, + 'Transloadit-Client': this._clientName, 'User-Agent': undefined, // Remove got's user-agent ...(this._authToken ? { Authorization: `Bearer ${this._authToken}` } : {}), ...headers, diff --git a/packages/node/test/unit/test-transloadit-client.test.ts b/packages/node/test/unit/test-transloadit-client.test.ts index 1b5f83c2..2fc7066a 100644 --- a/packages/node/test/unit/test-transloadit-client.test.ts +++ b/packages/node/test/unit/test-transloadit-client.test.ts @@ -388,6 +388,25 @@ describe('Transloadit', () => { expect.objectContaining({ headers: { 'Transloadit-Client': `node-sdk:${version}` } }), ) }) + + it('should allow overriding the "Transloadit-Client" header', async () => { + const client = new Transloadit({ + authKey: 'foo_key', + authSecret: 'foo_secret', + clientName: 'mcp-server:1.2.3', + }) + + const get = mockGot('get') + + const url = '/some-url' + // @ts-expect-error This tests private internals + await client._remoteJson({ url, method: 'get', isTrustedUrl: true }) + + expect(get).toHaveBeenCalledWith( + expect.any(String), + expect.objectContaining({ headers: { 'Transloadit-Client': 'mcp-server:1.2.3' } }), + ) + }) }) describe('getSignedSmartCDNUrl', () => {