@mongoosejs/studio 0.6.0 → 0.6.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +38 -0
- package/README.md +6 -5
- package/docs/mcp-oauth.md +5 -4
- package/express.js +4 -3
- package/frontend/index.js +1 -1
- package/frontend/public/app.js +1 -1
- package/index.d.ts +1 -1
- package/nest.d.ts +1 -0
- package/package.json +1 -1
package/CHANGELOG.md
ADDED
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
## 0.6.1
|
|
4
|
+
|
|
5
|
+
### Safer MCP defaults with API keys
|
|
6
|
+
|
|
7
|
+
MCP now defaults to disabled when Mongoose Studio is configured with an `apiKey`. Existing API-key integrations therefore continue to start without requiring additional MCP configuration.
|
|
8
|
+
|
|
9
|
+
To enable OAuth-protected MCP, set `mcp: true` and provide `publicUrl` with the publicly reachable base URL where Mongoose Studio is mounted:
|
|
10
|
+
|
|
11
|
+
```javascript
|
|
12
|
+
app.use('/studio', await studio('/studio/api', mongoose, {
|
|
13
|
+
apiKey: process.env.MONGOOSE_STUDIO_API_KEY,
|
|
14
|
+
mcp: true,
|
|
15
|
+
publicUrl: 'https://myproduct.app/studio'
|
|
16
|
+
}));
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
Mongoose Studio only requires `publicUrl` when both `apiKey` and `mcp: true` are set. Without an API key, MCP remains enabled by default and protected by `bindIp`.
|
|
20
|
+
|
|
21
|
+
## 0.6.0
|
|
22
|
+
|
|
23
|
+
### MCP support
|
|
24
|
+
|
|
25
|
+
Mongoose Studio now serves an MCP endpoint at `<mount>/mcp` using the same access controls as the rest of Mongoose Studio.
|
|
26
|
+
|
|
27
|
+
- MCP is enabled by default. Without an API key, access is protected by `bindIp`, so only clients running on the same machine can connect by default.
|
|
28
|
+
- Set `mcp: false` to disable the MCP endpoint and its OAuth discovery metadata.
|
|
29
|
+
- With an `apiKey`, MCP uses OAuth and requires `publicUrl` containing the publicly reachable base URL where Mongoose Studio is mounted, such as `https://myproduct.app/studio`.
|
|
30
|
+
|
|
31
|
+
```javascript
|
|
32
|
+
app.use('/studio', await studio('/studio/api', mongoose, {
|
|
33
|
+
apiKey: process.env.MONGOOSE_STUDIO_API_KEY,
|
|
34
|
+
publicUrl: 'https://myproduct.app/studio'
|
|
35
|
+
}));
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
Mongoose Studio throws an error during setup when MCP is enabled with an `apiKey` but `publicUrl` is missing.
|
package/README.md
CHANGED
|
@@ -56,23 +56,24 @@ app.use('/studio', await studio('/studio/api', mongoose, {
|
|
|
56
56
|
}));
|
|
57
57
|
```
|
|
58
58
|
|
|
59
|
-
|
|
60
|
-
Set `mcp: false` to turn it off
|
|
59
|
+
Without an API key, the Express integration exposes a Streamable HTTP MCP endpoint at `/studio/mcp` by default.
|
|
60
|
+
Set `mcp: false` to turn it off.
|
|
61
61
|
It provides authorized Dashboard and Model actions, plus `Script.createScript`, as MCP tools.
|
|
62
62
|
With a Pro API key, pass the logged-in Studio access token in the `Authorization` header (either directly or as a bearer token); tools receive that user's roles and permissions.
|
|
63
|
-
Without workspace authentication, the MCP endpoint uses the same localhost and `bindIp` restrictions as the rest of Studio.
|
|
63
|
+
Without workspace authentication, the MCP endpoint uses the same localhost and `bindIp` restrictions as the rest of Mongoose Studio.
|
|
64
64
|
|
|
65
65
|
#### Connecting ChatGPT or Claude with OAuth
|
|
66
66
|
|
|
67
|
-
With a Pro API key, `/studio/mcp`
|
|
67
|
+
With a Pro API key, MCP is disabled by default. Set `mcp: true` to expose `/studio/mcp` as an OAuth 2.1 protected resource so MCP clients such as ChatGPT and Claude can connect to it directly.
|
|
68
68
|
Point the client at your `/studio/mcp` URL and it will discover the Mongoose Studio authorization server, walk the user through signing in and approving access, and receive a short-lived access token.
|
|
69
69
|
Users review and revoke these connections from their Mongoose Studio account page, and the access an AI client gets can never exceed the access the user who approved it already has.
|
|
70
70
|
|
|
71
71
|
Mongoose Studio advertises itself to MCP clients using its externally reachable URL.
|
|
72
|
-
When MCP
|
|
72
|
+
When enabling MCP with a Pro API key, also set `publicUrl` to the URL where Mongoose Studio is mounted:
|
|
73
73
|
|
|
74
74
|
```javascript
|
|
75
75
|
opts.publicUrl = 'https://app.example.com/studio';
|
|
76
|
+
opts.mcp = true;
|
|
76
77
|
```
|
|
77
78
|
|
|
78
79
|
Mongoose Studio finds the authorization server through the mothership it is already configured to use, so it needs no separate authorization server configuration.
|
package/docs/mcp-oauth.md
CHANGED
|
@@ -84,17 +84,18 @@ They can only narrow what the host application already allows: `maxTimeMS` is ca
|
|
|
84
84
|
|
|
85
85
|
## Configuration
|
|
86
86
|
|
|
87
|
-
|
|
88
|
-
|
|
87
|
+
MCP is disabled by default when Mongoose Studio has a Pro API key.
|
|
88
|
+
To enable it, set `mcp: true` and set `publicUrl` to the externally reachable URL where Mongoose Studio is mounted:
|
|
89
89
|
|
|
90
90
|
```javascript
|
|
91
91
|
app.use('/studio', await studio('/studio/api', mongoose, {
|
|
92
92
|
apiKey: process.env.MONGOOSE_STUDIO_API_KEY,
|
|
93
|
+
mcp: true,
|
|
93
94
|
publicUrl: 'https://app.example.com/studio'
|
|
94
95
|
}));
|
|
95
96
|
```
|
|
96
97
|
|
|
97
|
-
Pass `mcp: false` to serve Studio without an MCP endpoint at all.
|
|
98
|
+
Pass `mcp: false` to serve Mongoose Studio without an MCP endpoint at all.
|
|
98
99
|
Neither the endpoint nor its protected resource metadata is then mounted, so there is nothing for an MCP client to discover.
|
|
99
100
|
Without an API key, the MCP endpoint follows the normal localhost or `bindIp` restrictions and does not mount OAuth protected resource metadata.
|
|
100
101
|
|
|
@@ -102,5 +103,5 @@ Mongoose Studio registers that URL with the authorization server the first time
|
|
|
102
103
|
It advertises the configured mothership's origin in `authorization_servers`, keeping authentication with the same service Mongoose Studio already uses.
|
|
103
104
|
|
|
104
105
|
Browser based MCP clients, claude.ai among them, run discovery from the page rather than from a server.
|
|
105
|
-
Studio therefore serves the MCP endpoint and its metadata with CORS, and exposes `WWW-Authenticate` via `Access-Control-Expose-Headers`.
|
|
106
|
+
Mongoose Studio therefore serves the MCP endpoint and its metadata with CORS, and exposes `WWW-Authenticate` via `Access-Control-Expose-Headers`.
|
|
106
107
|
Without that last header a browser hides the challenge from the client, and the client cannot find the authorization server at all.
|
package/express.js
CHANGED
|
@@ -17,7 +17,8 @@ const MCP_ACCESS_TOKEN_PREFIX = 'mcp_at_';
|
|
|
17
17
|
module.exports = async function mongooseStudioExpressApp(apiUrl, conn, options) {
|
|
18
18
|
const router = express.Router();
|
|
19
19
|
options = options ? { changeStream: true, ...options } : { changeStream: true };
|
|
20
|
-
|
|
20
|
+
options.mcp = options.mcp ?? !options.apiKey;
|
|
21
|
+
if (options.mcp && options.apiKey && !options.publicUrl) {
|
|
21
22
|
throw new Error('Mongoose Studio requires the publicUrl option when MCP is enabled with an API key');
|
|
22
23
|
}
|
|
23
24
|
const hasBindIpOption = Object.prototype.hasOwnProperty.call(options, 'bindIp');
|
|
@@ -124,10 +125,10 @@ module.exports = async function mongooseStudioExpressApp(apiUrl, conn, options)
|
|
|
124
125
|
// issued by the mothership. Mongoose Studio is the protected resource: it publishes the
|
|
125
126
|
// metadata that points clients at the authorization server, and resolves each
|
|
126
127
|
// token to its current grant before handling the request.
|
|
127
|
-
const mcpEnabled = options.mcp
|
|
128
|
+
const mcpEnabled = options.mcp;
|
|
128
129
|
const registeredMCPResources = new Set();
|
|
129
130
|
const mcpAuthorizationServerUrl = new URL(mothershipUrl).origin;
|
|
130
|
-
const mcpResource = workspace ? canonicalize(`${options.publicUrl.replace(/\/+$/, '')}/mcp`) : null;
|
|
131
|
+
const mcpResource = mcpEnabled && workspace ? canonicalize(`${options.publicUrl.replace(/\/+$/, '')}/mcp`) : null;
|
|
131
132
|
|
|
132
133
|
async function registerMCPResource(resource) {
|
|
133
134
|
if (registeredMCPResources.has(resource)) {
|
package/frontend/index.js
CHANGED
|
@@ -37,7 +37,7 @@ module.exports = async function frontend(apiUrl, isLambda, options, workspace) {
|
|
|
37
37
|
baseURL: apiUrl,
|
|
38
38
|
isLambda,
|
|
39
39
|
mcp: options?.mcp !== false,
|
|
40
|
-
mcpUrl: workspaceBaseUrl ? `${workspaceBaseUrl}/mcp` : null,
|
|
40
|
+
mcpUrl: options?.mcp !== false && workspaceBaseUrl ? `${workspaceBaseUrl}/mcp` : null,
|
|
41
41
|
mothershipUrl: apiKey ? mothershipUrl : null,
|
|
42
42
|
workspace: workspaceData
|
|
43
43
|
};
|
package/frontend/public/app.js
CHANGED
|
@@ -66655,7 +66655,7 @@ var src_default = VueToastificationPlugin;
|
|
|
66655
66655
|
(module) {
|
|
66656
66656
|
|
|
66657
66657
|
"use strict";
|
|
66658
|
-
module.exports = /*#__PURE__*/JSON.parse('{"name":"@mongoosejs/studio","version":"0.6.
|
|
66658
|
+
module.exports = /*#__PURE__*/JSON.parse('{"name":"@mongoosejs/studio","version":"0.6.1","description":"AI-Powered Data Workspace for MongoDB: Turn your MongoDB data into dashboards, maps, and interactive workflows - powered by your Mongoose models and AI.","homepage":"https://mongoosestudio.app/","repository":{"type":"git","url":"https://github.com/mongoosejs/studio"},"license":"Apache-2.0","dependencies":{"@ai-sdk/anthropic":"2.x","@ai-sdk/google":"2.x","@ai-sdk/openai":"2.x","@modelcontextprotocol/sdk":"^1.30.1","ace-builds":"^1.43.6","ai":"5.x","archetype":"0.13.1","csv-stringify":"6.3.0","ejson":"^2.2.3","extrovert":"^0.2.1","marked":"15.0.12","mpath":"^0.9.0","node-inspect-extracted":"3.x","regexp.escape":"^2.0.1","tailwindcss":"3.4.0","time-commando":"1.0.1","typescript":"^6.0.2","vue":"3.x","vue-toastification":"^2.0.0-rc.5","webpack":"5.x","xss":"^1.0.15","zod":"^4.6.5"},"peerDependencies":{"@nestjs/common":"10.x || 11.x","mongoose":"7.x || 8.x || ^9.0.0"},"peerDependenciesMeta":{"@nestjs/common":{"optional":true}},"optionalPeerDependencies":{"@mongoosejs/task":"0.5.x || 0.6.x"},"devDependencies":{"@masteringjs/eslint-config":"0.1.1","axios":"1.2.2","dedent":"^1.6.0","eslint":"9.30.0","@nestjs/common":"^11.1.9","express":"4.x","mocha":"10.2.0","mongodb-memory-server":"^11.0.1","mongoose":"9.x","sinon":"^21.0.1"},"scripts":{"lint":"eslint .","seed":"node seed/index.js","start":"node ./local.js","tailwind":"tailwindcss -o ./frontend/public/tw.css","tailwind:watch":"tailwindcss -o ./frontend/public/tw.css --watch","test":"mocha test/*.test.js","test:frontend":"mocha test/frontend/*.test.js","eval:agent":"node eval/agent/run.js"}}');
|
|
66659
66659
|
|
|
66660
66660
|
/***/ }
|
|
66661
66661
|
|
package/index.d.ts
CHANGED
|
@@ -9,7 +9,7 @@ declare module '@mongoosejs/studio' {
|
|
|
9
9
|
apiKey?: string;
|
|
10
10
|
bindIp?: string | string[] | null;
|
|
11
11
|
maxTimeMS?: number;
|
|
12
|
-
/** Serve the MCP endpoint at `<mount>/mcp`. Defaults to true. */
|
|
12
|
+
/** Serve the MCP endpoint at `<mount>/mcp`. Defaults to true without apiKey and false with apiKey. */
|
|
13
13
|
mcp?: boolean;
|
|
14
14
|
readPreference?: 'primary' | 'secondaryPreferred' | 'secondary';
|
|
15
15
|
/** Public base URL Mongoose Studio is mounted on. Required when MCP and apiKey are enabled. */
|
package/nest.d.ts
CHANGED
|
@@ -10,6 +10,7 @@ declare module '@mongoosejs/studio/nest' {
|
|
|
10
10
|
apiKey?: string;
|
|
11
11
|
bindIp?: string | string[] | null;
|
|
12
12
|
maxTimeMS?: number;
|
|
13
|
+
/** Serve the MCP endpoint. Defaults to true without apiKey and false with apiKey. */
|
|
13
14
|
mcp?: boolean;
|
|
14
15
|
readPreference?: 'primary' | 'secondaryPreferred' | 'secondary';
|
|
15
16
|
publicUrl?: string;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@mongoosejs/studio",
|
|
3
|
-
"version": "0.6.
|
|
3
|
+
"version": "0.6.1",
|
|
4
4
|
"description": "AI-Powered Data Workspace for MongoDB: Turn your MongoDB data into dashboards, maps, and interactive workflows - powered by your Mongoose models and AI.",
|
|
5
5
|
"homepage": "https://mongoosestudio.app/",
|
|
6
6
|
"repository": {
|