Skip to content

MCP - #280

Merged
vkarpov15 merged 7 commits into
mainfrom
vkarpov15/mcp
Oct 6, 2026
Merged

MCP#280
vkarpov15 merged 7 commits into
mainfrom
vkarpov15/mcp

Conversation

@vkarpov15

Copy link
Copy Markdown
Member

No description provided.

@vkarpov15
vkarpov15 requested a balanced review from Copilot October 6, 2026 19:55
@vercel

vercel Bot commented Oct 6, 2026 •

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated
studio Ready Ready Preview Oct 6, 2026 7:56pm UTC

Request Review

@chatgpt-codex-connector

chatgpt-codex-connector Bot commented Oct 6, 2026 •

Copy link
Copy Markdown

Codex Review Summary

This comment shows the latest Codex review activity on this pull request.

Review Status Commit Review trigger
📝 Code Review ✅ Completed 2026-10-06T20:01:08.022736Z 5e7308f PR opened
ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review" or "@codex security review".

Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings.

@vkarpov15
vkarpov15 merged commit 1febe75 into main Oct 6, 2026
31 checks passed

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 5e7308fa94

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread express.js
Comment on lines +203 to +207
then(({ user, permissions }) => {
req._internals = req._internals || {};
req._internals.authorization = token;
req._internals.initiatedById = user._id;
req._internals.roles = permissions.roles;

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Enforce the grant's collection allowlist

When token introspection returns a restricted permissions.collections value, this middleware discards it and propagates only the coarse roles and operation limits. Every Model tool still accepts any registered model name, so a client granted access to one collection can read or mutate every collection permitted by its role. Preserve the resolved collection scope and enforce it before invoking Model actions.

Useful? React with 👍 / 👎.

Comment thread backend/authorize.js
'Model.updateDocuments': ['owner', 'admin', 'member']
'Model.updateDocuments': ['owner', 'admin', 'member'],
'Script.createScript': ['owner', 'admin', 'member', 'readonly'],
'Script.executeScript': ['owner', 'admin', 'member', 'readonly'],

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Remove readonly access from script execution

A user whose only role is readonly can call the regular Script.executeScript API for a script they own and run it with dryRun: false; sandbox scripts can issue writes through application models and collections. Marking the action mcp = false only hides the MCP tool and does not protect this API endpoint, so script execution should require a write-capable role.

Useful? React with 👍 / 👎.

Comment thread express.js
const mcpEnabled = options.mcp !== false;
const registeredMCPResources = new Set();
const mcpAuthorizationServerUrl = new URL(mothershipUrl).origin;
const mcpResource = workspace ? canonicalize(`${options.publicUrl.replace(/\/+$/, '')}/mcp`) : null;

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Skip MCP URL construction when MCP is disabled

With an API key, mcp: false, and no publicUrl, the validation at the start of this function intentionally permits startup, but workspace is then populated and this unconditional options.publicUrl.replace(...) throws. This prevents API-key deployments from disabling MCP unless they provide an otherwise unnecessary public URL; construct the resource only when MCP is enabled.

Useful? React with 👍 / 👎.

const doc = await Model.
findById(documentId).
setOptions(omitNullish({ sanitizeFilter: true, maxTimeMS: options?.maxTimeMS })).
setOptions(readOperationOptions(options, { sanitizeFilter: true })).

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Forward request constraints to single-document reads

For an OAuth request with a lower maxTimeMS or a secondary read preference, this passes { sanitizeFilter: true } as the request params instead of passing params and supplying the flag as the third argument. Consequently getDocument ignores the grant's limits and reads with host defaults; validateDocument contains the identical call. Pass params through and provide { sanitizeFilter: true } as extra so these individual operations honor the delegated policy.

AGENTS.md reference: AGENTS.md:L5-L7

Useful? React with 👍 / 👎.

Comment thread backend/mcp.js
Comment on lines +99 to +101
for await (const chunk of { [Symbol.asyncIterator]: () => iterator }) {
chunks.push(chunk);
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Exclude the unbounded change stream from MCP

When Model.streamDocumentChanges is called as an MCP tool, this loop buffers its async iterator until completion, but that generator normally waits for the process-wide change stream to end and therefore never returns a tool result. Cancellation also calls iterator.return() while the generator is blocked on its unresolved queue promise, so the request and listener can remain stuck. Either omit this action from MCP or implement abort-aware streaming instead of collecting it as a finite result.

Useful? React with 👍 / 👎.

Comment on lines +28 to +32
selectedRunLabel() {
return this.selectedRunMode === 'dryRun' ? 'Dry Run' : 'Run';
},
isDryRunResult() {
return this.script?.executionFinishedAt != null && this.script?.dryRun === true;

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Inline the one-use display computations

selectedRunLabel and isDryRunResult are single-expression computed properties used only once in the template, adding indirection without reuse. Inline these expressions at their display sites as required by the frontend locality convention.

AGENTS.md reference: AGENTS.md:L74-L74

Useful? React with 👍 / 👎.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot review overview

🟡 Changes recommended

Delegated OAuth limits and read-only boundaries are not consistently enforced, and several supported configurations fail or advertise unusable MCP URLs.

Review effort: Balanced
Findings: 8 High severity · 5 Medium severity · 7 Low severity

Open (20)
What changed in this PR

Adds MCP/OAuth support to Mongoose Studio, including delegated database tools, standalone script review/execution, and per-request query limits.

Changes:

  • Adds Streamable HTTP MCP endpoints, OAuth metadata, and authorization.
  • Adds script persistence, execution, dry runs, and frontend review UI.
  • Propagates maxTimeMS and read preferences across database operations.
File Description
vercel.d.ts Adds read-preference typing.
test/​setup.test.js Exposes shared backend options.
test/​Script.executeScript.test.js Tests script lifecycle and dry runs.
test/​mcpOAuth.test.js Tests OAuth, CORS, and metadata.
test/​mcp.test.js Tests MCP tools and authorization.
test/​maxTimeMS.test.js Tests per-request operation limits.
test/​frontend/​script.test.js Tests script frontend behavior.
test/​archetypeToZodSchema.test.js Tests schema conversion.
README.md Documents MCP configuration and OAuth.
package.json Adds MCP SDK and Zod dependencies.
nest.d.ts Adds MCP option typings.
index.d.ts Expands Express option typings.
frontend/​src/​script/​script.js Implements script review and execution.
frontend/​src/​script/​script.html Adds the script interface.
frontend/​src/​routes.js Adds MCP and script routes.
frontend/​src/​navbar/​navbar.js Adds MCP availability state.
frontend/​src/​navbar/​navbar.html Adds MCP navigation links.
frontend/​src/​mcp/​mcp.js Computes and copies the MCP URL.
frontend/​src/​mcp/​mcp.html Adds MCP connection guidance.
frontend/​src/​index.js Tracks scripts and guards MCP routes.
frontend/​src/​api.js Adds Script API wrappers.
frontend/​index.js Publishes MCP frontend configuration.
express.js Mounts and authenticates MCP endpoints.
eval/​agent/​run.js Updates sandbox construction.
eslint.config.js Registers the URL global.
docs/​mcp-oauth.md Documents delegated OAuth behavior.
CLAUDE.md Removes duplicate guidance.
backend/​util/​archetypeToZodSchema.js Converts action schemas to Zod.
backend/​sandbox/​createScriptDb.js Applies sandbox operation limits.
backend/​sandbox/​createSandbox.js Accepts read-operation options.
backend/​next.js Shares workspace data with actions.
backend/​netlify.js Shares workspace data with actions.
backend/​mcp.js Exposes authorized actions as MCP tools.
backend/​integrations/​mothership.js Adds OAuth mothership requests.
backend/​index.js Registers the script model.
backend/​helpers/​readOperationOptions.js Resolves read preferences and limits.
backend/​helpers/​operationOptions.js Resolves per-request time limits.
backend/​db/​scriptSchema.js Defines persisted scripts and results.
backend/​authorize.js Adds authorization for new actions.
backend/​actions/​Task/​runTask.js Applies request time limits.
backend/​actions/​Task/​rescheduleTask.js Applies request time limits.
backend/​actions/​Task/​getTasksOverTime.js Applies request time limits.
backend/​actions/​Task/​getTasks.js Applies request time limits.
backend/​actions/​Task/​getTaskOverview.js Applies request time limits.
backend/​actions/​Task/​cancelTask.js Applies request time limits.
backend/​actions/​Script/​index.js Exports Script actions.
backend/​actions/​Script/​getScript.js Loads authorized scripts.
backend/​actions/​Script/​executeScript.js Executes and records scripts.
backend/​actions/​Script/​createScript.js Creates reviewable scripts.
backend/​actions/​Model/​validateDocument.js Adds MCP metadata and limits.
backend/​actions/​Model/​updateDocuments.js Adds metadata and request limits.
backend/​actions/​Model/​updateDocument.js Adds metadata and request limits.
backend/​actions/​Model/​streamDocumentChanges.js Exposes change streaming metadata.
backend/​actions/​Model/​streamChatMessage.js Exposes chat streaming metadata.
backend/​actions/​Model/​listModels.js Adds MCP metadata.
backend/​actions/​Model/​getSuggestedProjection.js Adds MCP metadata.
backend/​actions/​Model/​getIndexes.js Adds MCP metadata.
backend/​actions/​Model/​getEstimatedDocumentCounts.js Applies delegated read options.
backend/​actions/​Model/​getDocumentsStream.js Applies delegated read options.
backend/​actions/​Model/​getDocuments.js Applies delegated read options.
backend/​actions/​Model/​getDocument.js Applies delegated read options.
backend/​actions/​Model/​getCollectionInfo.js Applies delegated read options.
backend/​actions/​Model/​exportQueryResults.js Applies delegated read options.
backend/​actions/​Model/​executeDocumentScript.js Applies limits inside scripts.
backend/​actions/​Model/​dropIndex.js Adds destructive-action metadata.
backend/​actions/​Model/​dropCollection.js Adds destructive-action metadata.
backend/​actions/​Model/​deleteDocuments.js Adds metadata and request limits.
backend/​actions/​Model/​deleteDocument.js Adds metadata and request limits.
backend/​actions/​Model/​createDocument.js Adds MCP metadata.
backend/​actions/​Model/​createChatMessage.js Adds MCP metadata.
backend/​actions/​Model/​analyzeSchema.js Applies delegated read options.
backend/​actions/​Model/​addField.js Adds metadata and request limits.
backend/​actions/​index.js Exports Script actions.
backend/​actions/​Dashboard/​updateDashboard.js Adds metadata and request limits.
backend/​actions/​Dashboard/​getDashboards.js Adds MCP metadata and limits.
backend/​actions/​Dashboard/​getDashboard.js Applies sandbox request limits.
backend/​actions/​Dashboard/​deleteDashboard.js Adds destructive metadata and limits.
backend/​actions/​Dashboard/​createDashboard.js Adds MCP metadata.
backend/​actions/​ChatThread/​toggleAgentMode.js Applies request time limits.
backend/​actions/​ChatThread/​streamChatMessage.js Applies request time limits.
backend/​actions/​ChatThread/​shareChatThread.js Applies request time limits.
backend/​actions/​ChatThread/​listChatThreads.js Applies request time limits.
backend/​actions/​ChatThread/​getChatThread.js Applies request time limits.
backend/​actions/​ChatThread/​createChatMessage.js Applies request time limits.
backend/​actions/​ChatMessage/​executeScript.js Applies delegated sandbox limits.
AGENTS.md Expands repository development guidance.

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment on lines +225 to +226
module.exports.paramsType = GetDashboardParams;
module.exports.tags = ['readOnly'];
Comment on lines +39 to +40
module.exports.paramsType = GetDocumentsParams;
module.exports.tags = ['readOnly'];
Comment on lines +82 to +83
module.exports.paramsType = StreamChatMessageParams;
module.exports.tags = ['readOnly'];
Comment on lines +126 to +127
module.exports.paramsType = StreamDocumentChangesParams;
module.exports.tags = ['readOnly'];
Comment thread backend/authorize.js
'Model.updateDocuments': ['owner', 'admin', 'member']
'Model.updateDocuments': ['owner', 'admin', 'member'],
'Script.createScript': ['owner', 'admin', 'member', 'readonly'],
'Script.executeScript': ['owner', 'admin', 'member', 'readonly'],
Comment on lines +106 to +108
mcpEnabled() {
return window.MONGOOSE_STUDIO_CONFIG.mcp !== false;
},
Comment on lines +25 to +27
<button
class="px-1.5 py-1.5 text-sm bg-primary hover:bg-primary-hover text-primary-text border-l border-black/10 rounded-r-md"
@click.stop="showRunDropdown = !showRunDropdown">
</button>
</div>
</div>
<pre v-else class="whitespace-pre-wrap !my-0 bg-muted"><code ref="code" class="language-javascript" v-text="script.script"></code></pre>
Comment on lines +25 to +27
canUseDryRun() {
return this.state.capabilities?.supportsTransactions !== false;
},
Comment on lines +28 to +32
selectedRunLabel() {
return this.selectedRunMode === 'dryRun' ? 'Dry Run' : 'Run';
},
isDryRunResult() {
return this.script?.executionFinishedAt != null && this.script?.dryRun === true;

This branch was successfully deployed

1 active deployment
Preview — 5e7308fa Deployed Oct 6, 2026 by vercel[bot]
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants