Skip to content

Add /mcp/chatgpt-app with fixed single-operation tools for the OpenAI plugin - #1226

Merged
helpcodeai merged 3 commits into
mainfrom
feat/chatgpt-app-endpoint
Oct 24, 2026
Merged

helpcodeai merged 3 commits into
mainfrom
feat/chatgpt-app-endpoint

Conversation

@helpcodeai

Copy link
Copy Markdown
Contributor

Summary

OpenAI rejected the AnythingMCP plugin twice. Its review flags the shared endpoint's meta-tools (search_tools, describe_tool, run_read_tool, run_write_tool, run_read_steps, kg_how_to_obtain) as "operations not individually exposed", and the plugin guidelines now say: "Do not use discovery, operation selection, or schema fetching with a generic executor to enable operations not individually exposed for review." The review team confirmed on 23 Oct that they will not discuss it further.

Plugins approved after that rule (a read-only SQL database plugin, an integration-hub status plugin, an organization-data plugin) expose fixed single-operation tools. This PR adds a dedicated endpoint for a new OpenAI plugin submission that does the same, without touching what Claude or existing ChatGPT custom plugins use.

Changes

  • New POST /mcp/chatgpt-app (declared before :serverId; GET/DELETE answer 405 like the other stateless routes). It serves 8 fixed tools, all read-only, each with all hints set explicitly, and none takes a tool name or free-form arguments:
    • anythingmcp_list_connectors, anythingmcp_list_databases, anythingmcp_get_database_schema, anythingmcp_get_query_examples, anythingmcp_query_database, anythingmcp_get_connector_activity, anythingmcp_get_workspace_guide, anythingmcp_get_configuration_url
  • chatgpt-app-toolset.ts (no Nest, like shared-toolset.ts): the database tools map to the connector's generated get_database_schema / get_example_queries / execute_query tools and run through the same deps.execute path (scope, licence check, audit row). Only read-only database connectors are queried; a connector with write access is listed as not queryable and never run. The engine's existing guard still refuses non-SELECT and stacked statements. Connection URLs never leave the server (the engine is derived from the scheme only).
  • serveSharedToolset takes a variant; the chatgpt-app variant skips the setup-permission lookup (no setup tools) and builds the new tool set. Operator credentials without a user (static key) get 403.
  • McpServersService.activityByConnector: calls / failures / last call / last failure per connector over N days, counts only, grouped on the (connector_id, created_at) index.
  • Docs: docs/integrations/chatgpt.md section on the endpoint.

Cloud and self-hosted: the endpoint behaves the same in both modes and is independent of MCP_SHARED_ENDPOINT_TOOLS. /mcp (Claude directory toolset and the chatgpt profile for custom plugins on bare /mcp) and /mcp/<serverId> are unchanged.

Type

  • Bug fix
  • New feature
  • Documentation
  • Refactoring
  • Performance improvement
  • Other (describe below)

Testing

  • Added/updated unit tests
  • Tested manually (describe steps below)
  • No tests needed (explain why)

Commands (working directory packages/backend, after npx prisma generate):

  • npx tsc --noEmit -p tsconfig.json: passed
  • npm run lint: 0 errors, 11 existing warnings in untouched files (its --fix rewrote two unrelated spec files; reverted)
  • npm test: 755 suites passed, 4 skipped; 22,455 tests passed, 1,550 skipped
  • New: chatgpt-app-toolset.spec.ts (fixed list, no executor shape, read-only only, role hides query tool, ambiguity, no URL leak, activity) and chatgpt-app.controller.spec.ts (fixed + direct mode, tenant isolation, MCP role, no setup lookup, 403 for static credentials)

Manual end to end, local backend built from this branch against a separate Postgres database with a small orders/customers dataset, called with a per-user MCP API key:

  • initialize returns the new instructions; tools/list returns the 8 tools with explicit hints
  • anythingmcp_get_database_schema and an aggregate SELECT … GROUP BY query returned rows
  • DELETE FROM orders → "Only SELECT queries are allowed…"; SELECT 1; DROP TABLE orders → "Only a single SQL statement is allowed…"
  • A connector with readOnly: false → refused, never executed
  • anythingmcp_get_connector_activity counted the calls above
  • Unauthenticated POST → 401 with resource_metadata pointing at /.well-known/oauth-protected-resource/mcp/chatgpt-app, which returns resource: …/mcp/chatgpt-app; GET → 405
  • The SSRF guard blocked the loopback database until SSRF_ALLOW_LOCALHOST=true was set for the local run (expected)

Checklist

  • My code follows the existing code style
  • I have tested my changes locally
  • I have updated documentation (if applicable)
  • All existing tests pass (npm test)
  • This PR has a descriptive title

Related Issues

Relates to the OpenAI plugin directory submission (rejected 29 Sep and 20 Oct 2026).

helpcodeai and others added 2 commits October 24, 2026 11:28
… plugin

OpenAI's plugin review refuses the shared endpoint's search/describe/run meta-tools ("operations not individually exposed"). The new endpoint serves a fixed set where each tool is one operation: read-only database queries with schema and dialect examples, connector list and setup state, per-connector activity counts, workspace notes and the dashboard link. Only read-only database connectors are queried. Same auth, grant and role scope as /mcp; /mcp and /mcp/<serverId> are unchanged.
@helpcodeai
helpcodeai enabled auto-merge (squash) October 24, 2026 18:49
@helpcodeai
helpcodeai merged commit 0a30133 into main Oct 24, 2026
14 checks passed
@helpcodeai
helpcodeai deleted the feat/chatgpt-app-endpoint branch October 24, 2026 19:39
@github-actions github-actions Bot locked and limited conversation to collaborators Oct 24, 2026
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant