Skip to content

Commit f25eb06

Browse files
release: 12.4.0 (#600)
* chore(internal): remove redundant imports config * fix(mcp): fix tool description of jq_filter * fix(mcp): reverse validJson capability option and limit scope * fix(mcp): avoid sending `jq_filter` to base API * feat(mcp): add logging when environment variable is set * codegen metadata * codegen metadata * feat(mcp): remote server with passthru auth * codegen metadata * feat(api): expose authorizationToken as valid auth mechanism * chore: update error message on instantiation * release: 12.4.0 * update changelog --------- Co-authored-by: stainless-app[bot] <142633134+stainless-app[bot]@users.noreply.github.com> Co-authored-by: Justin Sanford <[email protected]>
1 parent d9b96db commit f25eb06

File tree

114 files changed

+593
-324
lines changed

Some content is hidden

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

114 files changed

+593
-324
lines changed

.release-please-manifest.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,3 @@
11
{
2-
".": "12.3.0"
2+
".": "12.4.0"
33
}

.stats.yml

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
11
configured_endpoints: 107
2-
openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/mux%2Fmux-323c1dc63b7a75cbabd3a79dcf80ca0afc9c0ae234f4323a39240a4a841583b9.yml
3-
openapi_spec_hash: e8fda4e033c6d0e7bc9ee4c629c232fa
4-
config_hash: 16b19b97f99dd7265b4619c5a999c751
2+
openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/mux%2Fmux-ba7ebfd893a1c5d082d55cddaec2ff9219072c9abd96442357aad1748e421483.yml
3+
openapi_spec_hash: 94fd98fcb8414d6c70a6ad7593ffcfa4
4+
config_hash: 06e26125693367671f74a6d70d1f3333

CHANGELOG.md

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,28 @@
11
# Changelog
22

3+
## 12.4.0 (2025-08-05)
4+
5+
Full Changelog: [v12.3.0...v12.4.0](https://github.com/muxinc/mux-node-sdk/compare/v12.3.0...v12.4.0)
6+
7+
### Features
8+
9+
* **api:** expose authorizationToken as valid auth mechanism for remote MCP server ([cbd38d5](https://github.com/muxinc/mux-node-sdk/commit/cbd38d5cf18966172b9f0aeb947253c67c47be0b))
10+
* **mcp:** add logging when environment variable is set ([4b25b46](https://github.com/muxinc/mux-node-sdk/commit/4b25b46de16bb2a9f381306d05c2c83141a475d1))
11+
* **mcp:** remote server with passthru auth ([a535888](https://github.com/muxinc/mux-node-sdk/commit/a535888596ae66eeb8a5a0a678c51461407716ef))
12+
13+
14+
### Bug Fixes
15+
16+
* **mcp:** avoid sending `jq_filter` to base API ([8d9d790](https://github.com/muxinc/mux-node-sdk/commit/8d9d7904342ad6fc03e49ec916bb29246f0d6637))
17+
* **mcp:** fix tool description of jq_filter ([56ce5dd](https://github.com/muxinc/mux-node-sdk/commit/56ce5dded1744997275b58d570fb868b51411c79))
18+
* **mcp:** reverse validJson capability option and limit scope ([8fecaf7](https://github.com/muxinc/mux-node-sdk/commit/8fecaf79e42e3b119e56593107c6dd9d94e94cdc))
19+
20+
21+
### Chores
22+
23+
* **internal:** remove redundant imports config ([6f1bd7b](https://github.com/muxinc/mux-node-sdk/commit/6f1bd7b3af54a78cb3685dfdf97e95098e4d208b))
24+
* update error message on instantiation ([ef387e2](https://github.com/muxinc/mux-node-sdk/commit/ef387e271e3fa57772f0762a232f317bcec8a896))
25+
326
## 12.3.0 (2025-07-24)
427

528
Full Changelog: [v12.2.0...v12.3.0](https://github.com/muxinc/mux-node-sdk/compare/v12.2.0...v12.3.0)

package.json

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "@mux/mux-node",
3-
"version": "12.3.0",
3+
"version": "12.4.0",
44
"description": "The official TypeScript library for the Mux API",
55
"author": "Mux <[email protected]>",
66
"types": "dist/index.d.ts",
@@ -59,10 +59,6 @@
5959
"./shims/web.js",
6060
"./shims/web.mjs"
6161
],
62-
"imports": {
63-
"@mux/mux-node": ".",
64-
"@mux/mux-node/*": "./src/*"
65-
},
6662
"exports": {
6763
"./_shims/auto/*": {
6864
"deno": {

packages/mcp-server/README.md

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
## Installation
44

5+
56
### Via MCP Client
67

78
There is a partial list of existing clients at [modelcontextprotocol.io](https://modelcontextprotocol.io/clients). If you already
@@ -20,7 +21,8 @@ For clients with a configuration JSON, it might look something like this:
2021
"MUX_TOKEN_SECRET": "my secret",
2122
"MUX_WEBHOOK_SECRET": "My Webhook Secret",
2223
"MUX_SIGNING_KEY": "My Jwt Signing Key",
23-
"MUX_PRIVATE_KEY": "My Jwt Private Key"
24+
"MUX_PRIVATE_KEY": "My Jwt Private Key",
25+
"MUX_AUTHORIZATION_TOKEN": "my authorization token"
2426
}
2527
}
2628
}

packages/mcp-server/cloudflare-worker/src/index.ts

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -20,17 +20,17 @@ const serverConfig: ServerConfig = {
2020
key: 'tokenId',
2121
label: 'Token ID',
2222
description: '',
23-
required: true,
24-
default: undefined,
23+
required: false,
24+
default: null,
2525
placeholder: 'my token id',
2626
type: 'password',
2727
},
2828
{
2929
key: 'tokenSecret',
3030
label: 'Token Secret',
3131
description: '',
32-
required: true,
33-
default: undefined,
32+
required: false,
33+
default: null,
3434
placeholder: 'my secret',
3535
type: 'password',
3636
},
@@ -61,6 +61,15 @@ const serverConfig: ServerConfig = {
6161
placeholder: 'My Jwt Private Key',
6262
type: 'string',
6363
},
64+
{
65+
key: 'authorizationToken',
66+
label: 'Authorization Token',
67+
description: '',
68+
required: false,
69+
default: null,
70+
placeholder: 'my authorization token',
71+
type: 'password',
72+
},
6473
],
6574
};
6675

packages/mcp-server/package.json

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "@mux/mcp",
3-
"version": "12.3.0",
3+
"version": "12.4.0",
44
"description": "The official MCP Server for the Mux API",
55
"author": "Mux <[email protected]>",
66
"types": "dist/index.d.ts",
@@ -29,6 +29,7 @@
2929
"dependencies": {
3030
"@mux/mux-node": "file:../../dist/",
3131
"@modelcontextprotocol/sdk": "^1.11.5",
32+
"express": "^5.1.0",
3233
"jq-web": "https://github.com/stainless-api/jq-web/releases/download/v0.8.2/jq-web.tar.gz",
3334
"yargs": "^17.7.2",
3435
"@cloudflare/cabidela": "^0.2.4",
@@ -41,6 +42,7 @@
4142
"devDependencies": {
4243
"@anthropic-ai/dxt": "^0.2.0",
4344
"@types/jest": "^29.4.0",
45+
"@types/express": "^5.0.3",
4446
"@typescript-eslint/eslint-plugin": "8.31.1",
4547
"@typescript-eslint/parser": "8.31.1",
4648
"eslint": "^8.49.0",

packages/mcp-server/src/compat.ts

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -70,8 +70,11 @@ export function parseEmbeddedJSON(args: Record<string, unknown>, schema: Record<
7070
if (typeof value === 'string') {
7171
try {
7272
const parsed = JSON.parse(value);
73-
newArgs[key] = parsed;
74-
updated = true;
73+
// Only parse if result is a plain object (not array, null, or primitive)
74+
if (parsed && typeof parsed === 'object' && !Array.isArray(parsed)) {
75+
newArgs[key] = parsed;
76+
updated = true;
77+
}
7578
} catch (e) {
7679
// Not valid JSON, leave as is
7780
}

packages/mcp-server/src/headers.ts

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
2+
3+
import { type ClientOptions } from '@mux/mux-node/index';
4+
5+
import { IncomingMessage } from 'node:http';
6+
7+
export const parseAuthHeaders = (req: IncomingMessage): Partial<ClientOptions> => {
8+
if (req.headers.authorization) {
9+
const scheme = req.headers.authorization.slice(req.headers.authorization.search(' '));
10+
const value = req.headers.authorization.slice(scheme.length + 1);
11+
switch (scheme) {
12+
case 'Basic':
13+
const rawValue = Buffer.from(value).toString('base64');
14+
return {
15+
tokenId: rawValue.slice(0, rawValue.search(':')),
16+
tokenSecret: rawValue.slice(rawValue.search(':') + 1),
17+
};
18+
case 'Bearer':
19+
return { authorizationToken: req.headers.authorization.slice('Bearer '.length) };
20+
default:
21+
throw new Error(`Unsupported authorization scheme`);
22+
}
23+
}
24+
25+
const tokenId =
26+
req.headers['x-mux-token-id'] instanceof Array ?
27+
req.headers['x-mux-token-id'][0]
28+
: req.headers['x-mux-token-id'];
29+
const tokenSecret =
30+
req.headers['x-mux-token-secret'] instanceof Array ?
31+
req.headers['x-mux-token-secret'][0]
32+
: req.headers['x-mux-token-secret'];
33+
const authorizationToken =
34+
req.headers['x-mux-authorization-token'] instanceof Array ?
35+
req.headers['x-mux-authorization-token'][0]
36+
: req.headers['x-mux-authorization-token'];
37+
return { tokenId, tokenSecret, authorizationToken };
38+
};

packages/mcp-server/src/http.ts

Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,85 @@
1+
import { McpServer } from '@modelcontextprotocol/sdk/server/mcp';
2+
import { StreamableHTTPServerTransport } from '@modelcontextprotocol/sdk/server/streamableHttp.js';
3+
4+
import express from 'express';
5+
import { McpOptions } from './options';
6+
import { initMcpServer, newMcpServer } from './server';
7+
import { parseAuthHeaders } from './headers';
8+
import { Endpoint } from './tools';
9+
10+
const newServer = (mcpOptions: McpOptions, req: express.Request, res: express.Response): McpServer | null => {
11+
const server = newMcpServer();
12+
try {
13+
const authOptions = parseAuthHeaders(req);
14+
initMcpServer({
15+
server: server,
16+
clientOptions: {
17+
...authOptions,
18+
defaultHeaders: {
19+
'X-Stainless-MCP': 'true',
20+
},
21+
},
22+
mcpOptions,
23+
});
24+
} catch {
25+
res.status(401).json({
26+
jsonrpc: '2.0',
27+
error: {
28+
code: -32000,
29+
message: 'Unauthorized',
30+
},
31+
});
32+
return null;
33+
}
34+
35+
return server;
36+
};
37+
38+
const post = (defaultOptions: McpOptions) => async (req: express.Request, res: express.Response) => {
39+
const server = newServer(defaultOptions, req, res);
40+
// If we return null, we already set the authorization error.
41+
if (server === null) return;
42+
const transport = new StreamableHTTPServerTransport({
43+
// Stateless server
44+
sessionIdGenerator: undefined,
45+
});
46+
await server.connect(transport);
47+
await transport.handleRequest(req, res, req.body);
48+
};
49+
50+
const get = async (req: express.Request, res: express.Response) => {
51+
res.status(405).json({
52+
jsonrpc: '2.0',
53+
error: {
54+
code: -32000,
55+
message: 'Method not supported',
56+
},
57+
});
58+
};
59+
60+
const del = async (req: express.Request, res: express.Response) => {
61+
res.status(405).json({
62+
jsonrpc: '2.0',
63+
error: {
64+
code: -32000,
65+
message: 'Method not supported',
66+
},
67+
});
68+
};
69+
70+
export const launchStreamableHTTPServer = async (
71+
options: McpOptions,
72+
endpoints: Endpoint[],
73+
port: number | undefined,
74+
) => {
75+
const app = express();
76+
app.use(express.json());
77+
78+
app.get('/', get);
79+
app.post('/', post(options));
80+
app.delete('/', del);
81+
82+
console.error(`MCP Server running on streamable HTTP on port ${port}`);
83+
84+
app.listen(port);
85+
};

0 commit comments

Comments
 (0)