From 4fff3f989a03dc4f5696b8b3ce858dd1f98f02b2 Mon Sep 17 00:00:00 2001 From: Travis Fischer Date: Thu, 12 Jun 2025 05:32:58 +0700 Subject: [PATCH] =?UTF-8?q?=F0=9F=93=BA?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/__snapshots__/http-e2e.test.ts.snap | 4 +- .../src/__snapshots__/mcp-e2e.test.ts.snap | 96 ++++++++++--------- apps/e2e/src/mcp-fixtures.ts | 43 ++++----- apps/gateway/src/lib/durable-mcp-server.ts | 5 +- .../src/lib/resolve-origin-tool-call.ts | 7 +- .../load-agentic-config.test.ts.snap | 46 +-------- packages/types/src/openapi.d.ts | 15 +-- packages/types/src/tools.ts | 10 +- 8 files changed, 94 insertions(+), 132 deletions(-) diff --git a/apps/e2e/src/__snapshots__/http-e2e.test.ts.snap b/apps/e2e/src/__snapshots__/http-e2e.test.ts.snap index eeb75685..3cd4795e 100644 --- a/apps/e2e/src/__snapshots__/http-e2e.test.ts.snap +++ b/apps/e2e/src/__snapshots__/http-e2e.test.ts.snap @@ -1,6 +1,6 @@ // Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html -exports[`HTTP => MCP origin basic "add" tool call success > 5.0: POST @dev/test-basic-mcp/add 1`] = ` +exports[`HTTP => MCP origin basic "add" tool > 5.0: POST @dev/test-basic-mcp/add 1`] = ` [ { "text": "42", @@ -9,7 +9,7 @@ exports[`HTTP => MCP origin basic "add" tool call success > 5.0: POST @dev/test- ] `; -exports[`HTTP => MCP origin basic "add" tool call success > 5.1: GET @dev/test-basic-mcp/add 1`] = ` +exports[`HTTP => MCP origin basic "add" tool > 5.1: GET @dev/test-basic-mcp/add 1`] = ` [ { "text": "42", diff --git a/apps/e2e/src/__snapshots__/mcp-e2e.test.ts.snap b/apps/e2e/src/__snapshots__/mcp-e2e.test.ts.snap index cfa8c872..c9846a08 100644 --- a/apps/e2e/src/__snapshots__/mcp-e2e.test.ts.snap +++ b/apps/e2e/src/__snapshots__/mcp-e2e.test.ts.snap @@ -1,49 +1,5 @@ // Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html -exports[`MCP => MCP origin basic "echo" tool > 10.0: @dev/test-basic-mcp/mcp echo 1`] = ` -{ - "content": [ - { - "text": "{"nala":"kitten","num":123,"now":1749678890348}", - "type": "text", - }, - ], -} -`; - -exports[`MCP => MCP origin basic "echo" tool with empty body > 13.0: @dev/test-basic-mcp/mcp echo 1`] = ` -{ - "content": [ - { - "text": "{}", - "type": "text", - }, - ], -} -`; - -exports[`MCP => MCP origin basic "pure" tool > 11.0: @dev/test-basic-mcp/mcp echo 1`] = ` -{ - "content": [ - { - "text": "{"nala":"kitten","foo":"bar"}", - "type": "text", - }, - ], -} -`; - -exports[`MCP => MCP origin basic "pure" tool > 11.1: @dev/test-basic-mcp/mcp echo 1`] = ` -{ - "content": [ - { - "text": "{"nala":"kitten","foo":"bar"}", - "type": "text", - }, - ], -} -`; - exports[`MCP => OpenAPI origin basic @ 010332cf get_post success > 2.0: @dev/test-basic-openapi@010332cf/mcp get_post 1`] = ` { "content": [], @@ -204,6 +160,58 @@ nostrum rerum est autem sunt rem eveniet architecto", } `; +exports[`MCP => OpenAPI origin everything "echo" tool with empty body > 13.0: @dev/test-everything-openapi/mcp echo 1`] = ` +{ + "content": [], + "isError": false, + "structuredContent": {}, +} +`; + +exports[`MCP => OpenAPI origin everything "pure" tool > 11.0: @dev/test-everything-openapi/mcp echo 1`] = ` +{ + "content": [], + "isError": false, + "structuredContent": { + "foo": "bar", + "nala": "kitten", + }, +} +`; + +exports[`MCP => OpenAPI origin everything "pure" tool > 11.1: @dev/test-everything-openapi/mcp echo 1`] = ` +{ + "content": [], + "isError": false, + "structuredContent": { + "foo": "bar", + "nala": "kitten", + }, +} +`; + +exports[`MCP => OpenAPI origin everything "unpure_marked_pure" tool > 14.0: @dev/test-everything-openapi/mcp unpure_marked_pure 1`] = ` +{ + "content": [], + "isError": false, + "structuredContent": { + "nala": "cat", + "now": 1749674829923, + }, +} +`; + +exports[`MCP => OpenAPI origin everything "unpure_marked_pure" tool > 14.1: @dev/test-everything-openapi/mcp unpure_marked_pure 1`] = ` +{ + "content": [], + "isError": false, + "structuredContent": { + "nala": "cat", + "now": 1749674829923, + }, +} +`; + exports[`MCP => OpenAPI origin everything errors > 5.0: @dev/test-everything-openapi/mcp strict_additional_properties 1`] = ` { "content": [], diff --git a/apps/e2e/src/mcp-fixtures.ts b/apps/e2e/src/mcp-fixtures.ts index 54259758..9e4cdc91 100644 --- a/apps/e2e/src/mcp-fixtures.ts +++ b/apps/e2e/src/mcp-fixtures.ts @@ -128,7 +128,10 @@ export const fixtureSuites: MCPE2ETestFixtureSuite[] = [ type: 'text', text: JSON.stringify({ nala: 'kitten', num: 123, now }) } - ] + ], + _agenticMeta: { + cacheStatus: 'DYNAMIC' + } } }, { @@ -150,7 +153,10 @@ export const fixtureSuites: MCPE2ETestFixtureSuite[] = [ now: `${now}` }) } - ] + ], + _agenticMeta: { + cacheStatus: 'DYNAMIC' + } } } ] @@ -392,6 +398,7 @@ export const fixtureSuites: MCPE2ETestFixtureSuite[] = [ { title: 'MCP => MCP origin basic "echo" tool', path: '@dev/test-basic-mcp/mcp', + stableSnapshot: false, fixtures: [ { request: { @@ -417,6 +424,7 @@ export const fixtureSuites: MCPE2ETestFixtureSuite[] = [ { title: 'MCP => OpenAPI origin everything "pure" tool', path: '@dev/test-everything-openapi/mcp', + compareResponseBodies: true, fixtures: [ { request: { @@ -436,15 +444,10 @@ export const fixtureSuites: MCPE2ETestFixtureSuite[] = [ }, response: { isError: false, - content: [ - { - type: 'text', - text: JSON.stringify({ - nala: 'kitten', - foo: 'bar' - }) - } - ] + structuredContent: { + nala: 'kitten', + foo: 'bar' + } } }, { @@ -466,15 +469,10 @@ export const fixtureSuites: MCPE2ETestFixtureSuite[] = [ }, response: { isError: false, - content: [ - { - type: 'text', - text: JSON.stringify({ - nala: 'kitten', - foo: 'bar' - }) - } - ], + structuredContent: { + nala: 'kitten', + foo: 'bar' + }, _agenticMeta: { cacheStatus: 'HIT' } @@ -514,7 +512,7 @@ export const fixtureSuites: MCPE2ETestFixtureSuite[] = [ }, response: { isError: false, - content: [{ type: 'text', text: JSON.stringify({}) }] + structuredContent: {} } } ] @@ -523,7 +521,6 @@ export const fixtureSuites: MCPE2ETestFixtureSuite[] = [ title: 'MCP => OpenAPI origin everything "unpure_marked_pure" tool', path: '@dev/test-everything-openapi/mcp', compareResponseBodies: true, - only: true, fixtures: [ { request: { @@ -535,7 +532,7 @@ export const fixtureSuites: MCPE2ETestFixtureSuite[] = [ response: { isError: false, validate: (result) => { - const body = JSON.parse(result.content[0].text) + const body = result.structuredContent expect(body?.nala).toEqual('cat') expect(typeof body.now).toBe('number') expect(body.now).toBeGreaterThan(0) diff --git a/apps/gateway/src/lib/durable-mcp-server.ts b/apps/gateway/src/lib/durable-mcp-server.ts index 043afe5a..9909a324 100644 --- a/apps/gateway/src/lib/durable-mcp-server.ts +++ b/apps/gateway/src/lib/durable-mcp-server.ts @@ -71,7 +71,10 @@ export class DurableMcpServerBase extends McpAgent< return undefined } - if (!pricingPlanToolConfig?.enabled && !toolConfig.enabled) { + if ( + pricingPlanToolConfig?.enabled !== true && + toolConfig.enabled === false + ) { // Tool is disabled / hidden for all pricing plans return undefined } diff --git a/apps/gateway/src/lib/resolve-origin-tool-call.ts b/apps/gateway/src/lib/resolve-origin-tool-call.ts index ff37d379..a12de755 100644 --- a/apps/gateway/src/lib/resolve-origin-tool-call.ts +++ b/apps/gateway/src/lib/resolve-origin-tool-call.ts @@ -129,6 +129,7 @@ export async function resolveOriginToolCall({ const pricingPlanToolOverride = pricingPlan ? toolConfig.pricingPlanOverridesMap?.[pricingPlan.slug] : undefined + const isToolConfigEnabled = toolConfig.enabled ?? true // Check if this tool is configured for pricing-plan-specific overrides // which take precedence over the tool's default behavior. @@ -136,11 +137,11 @@ export async function resolveOriginToolCall({ if (pricingPlanToolOverride.enabled !== undefined) { assert( pricingPlanToolOverride.enabled, - toolConfig.enabled ? 403 : 404, + isToolConfigEnabled ? 403 : 404, `Tool "${tool.name}" is disabled for pricing plan "${pricingPlan.slug}"` ) } else { - assert(toolConfig.enabled, 404, `Tool "${tool.name}" is disabled`) + assert(isToolConfigEnabled, 404, `Tool "${tool.name}" is disabled`) } if (pricingPlanToolOverride.reportUsage !== undefined) { @@ -152,7 +153,7 @@ export async function resolveOriginToolCall({ rateLimit = pricingPlanToolOverride.rateLimit as RateLimit } } else { - assert(toolConfig.enabled, 404, `Tool "${tool.name}" is disabled`) + assert(isToolConfigEnabled, 404, `Tool "${tool.name}" is disabled`) } } else { if (cacheControl) { diff --git a/packages/platform/src/__snapshots__/load-agentic-config.test.ts.snap b/packages/platform/src/__snapshots__/load-agentic-config.test.ts.snap index 0b56df82..18054831 100644 --- a/packages/platform/src/__snapshots__/load-agentic-config.test.ts.snap +++ b/packages/platform/src/__snapshots__/load-agentic-config.test.ts.snap @@ -56,18 +56,12 @@ exports[`loadAgenticConfig > basic-openapi 1`] = ` ], "toolConfigs": [ { - "additionalProperties": true, - "enabled": true, "name": "get_posts", "pure": true, - "reportUsage": true, }, { - "additionalProperties": true, - "enabled": true, "name": "get_post", "pure": true, - "reportUsage": true, }, ], "version": undefined, @@ -159,7 +153,6 @@ exports[`loadAgenticConfig > everything-openapi 1`] = ` ], "toolConfigs": [ { - "additionalProperties": true, "enabled": true, "name": "get_user", "pricingPlanOverridesMap": { @@ -173,88 +166,53 @@ exports[`loadAgenticConfig > everything-openapi 1`] = ` "reportUsage": true, }, { - "additionalProperties": true, "enabled": false, "name": "disabled_tool", - "pure": false, - "reportUsage": true, }, { - "additionalProperties": true, - "enabled": true, "name": "disabled_for_free_plan_tool", "pricingPlanOverridesMap": { "free": { "enabled": false, }, }, - "pure": false, - "reportUsage": true, }, { - "additionalProperties": true, - "enabled": true, "name": "pure", "pure": true, - "reportUsage": true, }, { - "additionalProperties": true, - "enabled": true, "name": "unpure_marked_pure", "pure": true, - "reportUsage": true, }, { - "additionalProperties": true, "cacheControl": "public, max-age=7200, s-maxage=7200, stale-while-revalidate=3600", - "enabled": true, "name": "custom_cache_control_tool", - "pure": false, - "reportUsage": true, }, { - "additionalProperties": true, "cacheControl": "no-cache", - "enabled": true, "name": "no_cache_cache_control_tool", - "pure": false, - "reportUsage": true, }, { - "additionalProperties": true, "cacheControl": "no-store", - "enabled": true, "name": "no_store_cache_control_tool", - "pure": false, - "reportUsage": true, }, { - "additionalProperties": true, - "enabled": true, "name": "custom_rate_limit_tool", - "pure": false, "rateLimit": { "async": true, "interval": 30, "maxPerInterval": 10, }, - "reportUsage": true, }, { - "additionalProperties": true, - "enabled": true, "name": "disabled_rate_limit_tool", - "pure": false, "rateLimit": null, - "reportUsage": true, }, { - "additionalProperties": false, - "enabled": true, + "inputSchemaAdditionalProperties": false, "name": "strict_additional_properties", - "pure": false, - "reportUsage": true, + "outputSchemaAdditionalProperties": false, }, ], "version": undefined, diff --git a/packages/types/src/openapi.d.ts b/packages/types/src/openapi.d.ts index cb203d4b..17d72482 100644 --- a/packages/types/src/openapi.d.ts +++ b/packages/types/src/openapi.d.ts @@ -497,18 +497,13 @@ export interface components { ToolConfig: { /** @description Agentic tool name */ name: string; - /** @default true */ - enabled: boolean; - /** @default false */ - pure: boolean; + enabled?: boolean; + pure?: boolean; cacheControl?: string; - /** @default true */ - reportUsage: boolean; + reportUsage?: boolean; rateLimit?: components["schemas"]["RateLimit"] | null; - /** @default true */ - inputSchemaAdditionalProperties: boolean; - /** @default true */ - outputSchemaAdditionalProperties: boolean; + inputSchemaAdditionalProperties?: boolean; + outputSchemaAdditionalProperties?: boolean; /** @description Allows you to override this tool's behavior or disable it entirely for different pricing plans. This is a map of PricingPlan slug to PricingPlanToolOverrides for that plan. */ pricingPlanOverridesMap?: { [key: string]: components["schemas"]["PricingPlanToolOverride"]; diff --git a/packages/types/src/tools.ts b/packages/types/src/tools.ts index 2d0a3f55..f736a4e8 100644 --- a/packages/types/src/tools.ts +++ b/packages/types/src/tools.ts @@ -107,7 +107,7 @@ export const toolConfigSchema = z * * @default true */ - enabled: z.boolean().optional().default(true), + enabled: z.boolean().optional(), /** * Whether this tool's output is deterministic and idempotent given the @@ -122,7 +122,7 @@ export const toolConfigSchema = z * * @default false */ - pure: z.boolean().optional().default(false), + pure: z.boolean().optional(), /** * A custom `Cache-Control` header to use for caching this tool's responses. @@ -153,7 +153,7 @@ export const toolConfigSchema = z * * @default true */ - reportUsage: z.boolean().optional().default(true), + reportUsage: z.boolean().optional(), /** * Customize the default `requests`-based rate-limiting for this tool. @@ -177,7 +177,7 @@ export const toolConfigSchema = z * * @default true */ - inputSchemaAdditionalProperties: z.boolean().optional().default(true), + inputSchemaAdditionalProperties: z.boolean().optional(), /** * Whether to allow additional properties in the tool's output schema. @@ -189,7 +189,7 @@ export const toolConfigSchema = z * * @default true */ - outputSchemaAdditionalProperties: z.boolean().optional().default(true), + outputSchemaAdditionalProperties: z.boolean().optional(), /** * Allows you to override this tool's behavior or disable it entirely for