From e13308f801db55ea6b1023fad4f1822a707318d7 Mon Sep 17 00:00:00 2001 From: Travis Fischer Date: Fri, 6 Jun 2025 04:21:43 +0700 Subject: [PATCH] fix: e2e tests --- .../api-v1/deployments/create-deployment.ts | 2 +- .../api/src/api-v1/projects/create-project.ts | 8 ++- apps/e2e/src/__snapshots__/e2e.test.ts.snap | 30 ++++----- apps/e2e/src/fixtures.ts | 67 ++++++++++++------- .../gateway/src/lib/resolve-origin-request.ts | 17 ++--- packages/cli/src/lib/resolve-deployment.ts | 4 +- packages/hono/src/error-handler.ts | 2 +- .../load-agentic-config.test.ts.snap | 37 ++++++++-- .../platform/src/load-agentic-config.test.ts | 3 +- packages/platform/src/resolve-metadata.ts | 2 +- readme.md | 3 + 11 files changed, 113 insertions(+), 62 deletions(-) diff --git a/apps/api/src/api-v1/deployments/create-deployment.ts b/apps/api/src/api-v1/deployments/create-deployment.ts index f60b6216..935e9f4f 100644 --- a/apps/api/src/api-v1/deployments/create-deployment.ts +++ b/apps/api/src/api-v1/deployments/create-deployment.ts @@ -65,7 +65,7 @@ export function registerV1DeploymentsCreateDeployment( const logger = c.get('logger') const namespace = teamMember ? teamMember.teamSlug : user.username - const projectIdentifier = `${namespace}/${body.name}` + const projectIdentifier = `@${namespace}/${body.name}` assert( isValidProjectIdentifier(projectIdentifier), 400, diff --git a/apps/api/src/api-v1/projects/create-project.ts b/apps/api/src/api-v1/projects/create-project.ts index 5ed3d3af..8a783e8a 100644 --- a/apps/api/src/api-v1/projects/create-project.ts +++ b/apps/api/src/api-v1/projects/create-project.ts @@ -1,4 +1,5 @@ import { assert, parseZodSchema, sha256 } from '@agentic/platform-core' +import { isValidProjectIdentifier } from '@agentic/platform-validators' import { createRoute, type OpenAPIHono } from '@hono/zod-openapi' import type { AuthenticatedHonoEnv } from '@/lib/types' @@ -52,7 +53,12 @@ export function registerV1ProjectsCreateProject( const teamMember = c.get('teamMember') const namespace = teamMember ? teamMember.teamSlug : user.username - const identifier = `${namespace}/${body.name}` + const identifier = `@${namespace}/${body.name}` + assert( + isValidProjectIdentifier(identifier), + 400, + `Invalid project identifier "${identifier}"` + ) const [project] = await db .insert(schema.projects) diff --git a/apps/e2e/src/__snapshots__/e2e.test.ts.snap b/apps/e2e/src/__snapshots__/e2e.test.ts.snap index 905b6404..2e78dba0 100644 --- a/apps/e2e/src/__snapshots__/e2e.test.ts.snap +++ b/apps/e2e/src/__snapshots__/e2e.test.ts.snap @@ -1,6 +1,6 @@ // Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html -exports[`Basic GET caching > 3.0: GET dev/test-basic-openapi@b6e21206/getPost 1`] = ` +exports[`Basic GET caching > 3.0: GET @dev/test-basic-openapi@fc856666/getPost 1`] = ` { "body": "consectetur animi nesciunt iure dolore enim quia ad @@ -12,7 +12,7 @@ et est aut quod aut provident voluptas autem voluptas", } `; -exports[`Basic GET caching > 3.1: GET dev/test-basic-openapi@b6e21206/getPost?postId=9 1`] = ` +exports[`Basic GET caching > 3.1: GET @dev/test-basic-openapi@fc856666/getPost?postId=9 1`] = ` { "body": "consectetur animi nesciunt iure dolore enim quia ad @@ -24,7 +24,7 @@ et est aut quod aut provident voluptas autem voluptas", } `; -exports[`Basic GET caching > 3.2: GET dev/test-basic-openapi@b6e21206/get_post?postId=9 1`] = ` +exports[`Basic GET caching > 3.2: GET @dev/test-basic-openapi@fc856666/get_post?postId=9 1`] = ` { "body": "consectetur animi nesciunt iure dolore enim quia ad @@ -36,7 +36,7 @@ et est aut quod aut provident voluptas autem voluptas", } `; -exports[`Basic OpenAPI getPost success > 0.0: POST dev/test-basic-openapi/getPost 1`] = ` +exports[`Basic OpenAPI getPost success > 0.0: POST @dev/test-basic-openapi/getPost 1`] = ` { "body": "quia et suscipit suscipit recusandae consequuntur expedita et cum @@ -48,7 +48,7 @@ nostrum rerum est autem sunt rem eveniet architecto", } `; -exports[`Basic OpenAPI getPost success > 0.1: POST dev/test-basic-openapi@latest/getPost 1`] = ` +exports[`Basic OpenAPI getPost success > 0.1: POST @dev/test-basic-openapi@latest/getPost 1`] = ` { "body": "quia et suscipit suscipit recusandae consequuntur expedita et cum @@ -60,7 +60,7 @@ nostrum rerum est autem sunt rem eveniet architecto", } `; -exports[`Basic OpenAPI getPost success > 0.2: GET dev/test-basic-openapi/getPost 1`] = ` +exports[`Basic OpenAPI getPost success > 0.2: GET @dev/test-basic-openapi/getPost 1`] = ` { "body": "quia et suscipit suscipit recusandae consequuntur expedita et cum @@ -72,7 +72,7 @@ nostrum rerum est autem sunt rem eveniet architecto", } `; -exports[`Basic OpenAPI getPost success > 0.3: GET dev/test-basic-openapi@b6e21206/getPost?postId=1 1`] = ` +exports[`Basic OpenAPI getPost success > 0.3: GET @dev/test-basic-openapi@fc856666/getPost?postId=1 1`] = ` { "body": "quia et suscipit suscipit recusandae consequuntur expedita et cum @@ -84,7 +84,7 @@ nostrum rerum est autem sunt rem eveniet architecto", } `; -exports[`Basic OpenAPI getPost success > 0.4: GET dev/test-basic-openapi@b6e21206/get_post?postId=1 1`] = ` +exports[`Basic OpenAPI getPost success > 0.4: GET @dev/test-basic-openapi@fc856666/get_post?postId=1 1`] = ` { "body": "quia et suscipit suscipit recusandae consequuntur expedita et cum @@ -96,7 +96,7 @@ nostrum rerum est autem sunt rem eveniet architecto", } `; -exports[`Basic OpenAPI getPost success > 0.5: GET dev/test-basic-openapi@b6e21206/getPost 1`] = ` +exports[`Basic OpenAPI getPost success > 0.5: GET @dev/test-basic-openapi@fc856666/getPost 1`] = ` { "body": "quia et suscipit suscipit recusandae consequuntur expedita et cum @@ -108,7 +108,7 @@ nostrum rerum est autem sunt rem eveniet architecto", } `; -exports[`Basic POST caching > 4.0: POST dev/test-basic-openapi@b6e21206/get_post 1`] = ` +exports[`Basic POST caching > 4.0: POST @dev/test-basic-openapi@fc856666/get_post 1`] = ` { "body": "aut dicta possimus sint mollitia voluptas commodi quo doloremque iste corrupti reiciendis voluptatem eius rerum @@ -120,7 +120,7 @@ perferendis recusandae assumenda consectetur porro architecto ipsum ipsam", } `; -exports[`Basic POST caching > 4.1: POST dev/test-basic-openapi@b6e21206/get_post 1`] = ` +exports[`Basic POST caching > 4.1: POST @dev/test-basic-openapi@fc856666/get_post 1`] = ` { "body": "aut dicta possimus sint mollitia voluptas commodi quo doloremque iste corrupti reiciendis voluptatem eius rerum @@ -132,7 +132,7 @@ perferendis recusandae assumenda consectetur porro architecto ipsum ipsam", } `; -exports[`Bypass caching > 2.0: GET dev/test-basic-openapi@b6e21206/getPost 1`] = ` +exports[`Bypass caching > 2.0: GET @dev/test-basic-openapi@fc856666/getPost 1`] = ` { "body": "consectetur animi nesciunt iure dolore enim quia ad @@ -144,7 +144,7 @@ et est aut quod aut provident voluptas autem voluptas", } `; -exports[`Bypass caching > 2.1: GET dev/test-basic-openapi@b6e21206/getPost?postId=9 1`] = ` +exports[`Bypass caching > 2.1: GET @dev/test-basic-openapi@fc856666/getPost?postId=9 1`] = ` { "body": "consectetur animi nesciunt iure dolore enim quia ad @@ -156,7 +156,7 @@ et est aut quod aut provident voluptas autem voluptas", } `; -exports[`Bypass caching > 2.2: GET dev/test-basic-openapi@b6e21206/get_post?postId=9 1`] = ` +exports[`Bypass caching > 2.2: GET @dev/test-basic-openapi@fc856666/get_post?postId=9 1`] = ` { "body": "consectetur animi nesciunt iure dolore enim quia ad @@ -168,7 +168,7 @@ et est aut quod aut provident voluptas autem voluptas", } `; -exports[`Bypass caching > 2.3: GET dev/test-basic-openapi@b6e21206/get_post?postId=9 1`] = ` +exports[`Bypass caching > 2.3: GET @dev/test-basic-openapi@fc856666/get_post?postId=9 1`] = ` { "body": "consectetur animi nesciunt iure dolore enim quia ad diff --git a/apps/e2e/src/fixtures.ts b/apps/e2e/src/fixtures.ts index 6aff8f75..7aee89c6 100644 --- a/apps/e2e/src/fixtures.ts +++ b/apps/e2e/src/fixtures.ts @@ -49,7 +49,7 @@ export const fixtureSuites: E2ETestFixtureSuite[] = [ compareResponseBodies: true, fixtures: [ { - path: 'dev/test-basic-openapi/getPost', + path: '@dev/test-basic-openapi/getPost', request: { method: 'POST', json: { @@ -58,7 +58,7 @@ export const fixtureSuites: E2ETestFixtureSuite[] = [ } }, { - path: 'dev/test-basic-openapi@latest/getPost', + path: '@dev/test-basic-openapi@latest/getPost', request: { method: 'POST', json: { @@ -67,7 +67,7 @@ export const fixtureSuites: E2ETestFixtureSuite[] = [ } }, { - path: 'dev/test-basic-openapi/getPost', + path: '@dev/test-basic-openapi/getPost', request: { searchParams: { // all of these GET requests implicitly test type coercion since @@ -78,13 +78,13 @@ export const fixtureSuites: E2ETestFixtureSuite[] = [ } }, { - path: 'dev/test-basic-openapi@b6e21206/getPost?postId=1' + path: '@dev/test-basic-openapi@fc856666/getPost?postId=1' }, { - path: 'dev/test-basic-openapi@b6e21206/get_post?postId=1' + path: '@dev/test-basic-openapi@fc856666/get_post?postId=1' }, { - path: 'dev/test-basic-openapi@b6e21206/getPost', + path: '@dev/test-basic-openapi@fc856666/getPost', request: { searchParams: { postId: 1 @@ -97,7 +97,7 @@ export const fixtureSuites: E2ETestFixtureSuite[] = [ title: 'Basic OpenAPI getPost errors', fixtures: [ { - path: 'dev/test-basic-openapi/getPost', + path: '@dev/test-basic-openapi/getPost', response: { // Missing `postId` parameter. @@ -105,19 +105,19 @@ export const fixtureSuites: E2ETestFixtureSuite[] = [ } }, { - path: 'dev/test-basic-openapi@b6e21206/getPost?postId=foo', + path: '@dev/test-basic-openapi@fc856666/getPost?postId=foo', response: { status: 400 } }, { - path: 'dev/test-basic-openapi@000000/getPost', + path: '@dev/test-basic-openapi@00000000/getPost', response: { status: 404 } }, { - path: 'dev/test-basic-openapi/getPost', + path: '@dev/test-basic-openapi/getPost', request: { method: 'PUT', json: { @@ -129,13 +129,13 @@ export const fixtureSuites: E2ETestFixtureSuite[] = [ } }, { - path: 'dev/test-basic-openapi@latest/get_kittens?postId=1', + path: '@dev/test-basic-openapi@latest/get_kittens?postId=1', response: { status: 404 } }, { - path: 'dev/test-basic-openapi/getPost', + path: '@dev/test-basic-openapi/getPost', request: { searchParams: { // invalid `postId` field type @@ -147,7 +147,7 @@ export const fixtureSuites: E2ETestFixtureSuite[] = [ } }, { - path: 'dev/test-basic-openapi/getPost', + path: '@dev/test-basic-openapi/getPost', request: { method: 'POST', json: { @@ -159,7 +159,7 @@ export const fixtureSuites: E2ETestFixtureSuite[] = [ } }, { - path: 'dev/test-basic-openapi/getPost', + path: '@dev/test-basic-openapi/getPost', request: { method: 'POST', json: { @@ -172,7 +172,7 @@ export const fixtureSuites: E2ETestFixtureSuite[] = [ } }, { - path: 'dev/test-basic-openapi/getPost', + path: '@dev/test-basic-openapi/getPost', request: { method: 'POST', json: { @@ -185,7 +185,7 @@ export const fixtureSuites: E2ETestFixtureSuite[] = [ } }, { - path: 'dev/test-basic-openapi/getPost', + path: '@dev/test-basic-openapi/getPost', request: { method: 'POST', json: { @@ -199,7 +199,7 @@ export const fixtureSuites: E2ETestFixtureSuite[] = [ } }, { - path: 'dev/test-basic-openapi/getPost', + path: '@dev/test-basic-openapi/getPost', request: { searchParams: { postId: 1, @@ -219,7 +219,7 @@ export const fixtureSuites: E2ETestFixtureSuite[] = [ fixtures: [ { // ensure we bypass the cache for requests with `pragma: no-cache` - path: 'dev/test-basic-openapi@b6e21206/getPost', + path: '@dev/test-basic-openapi@fc856666/getPost', request: { headers: { pragma: 'no-cache' @@ -236,7 +236,7 @@ export const fixtureSuites: E2ETestFixtureSuite[] = [ }, { // ensure we bypass the cache for requests with `pragma: no-cache` - path: 'dev/test-basic-openapi@b6e21206/getPost?postId=9', + path: '@dev/test-basic-openapi@fc856666/getPost?postId=9', request: { headers: { 'cache-control': 'no-cache' @@ -250,7 +250,7 @@ export const fixtureSuites: E2ETestFixtureSuite[] = [ }, { // ensure we bypass the cache for requests with `cache-control: no-store` - path: 'dev/test-basic-openapi@b6e21206/get_post?postId=9', + path: '@dev/test-basic-openapi@fc856666/get_post?postId=9', request: { headers: { 'cache-control': 'no-store' @@ -263,7 +263,7 @@ export const fixtureSuites: E2ETestFixtureSuite[] = [ } }, { - path: 'dev/test-basic-openapi@b6e21206/get_post?postId=9', + path: '@dev/test-basic-openapi@fc856666/get_post?postId=9', request: { headers: { 'cache-control': 'max-age=0, must-revalidate, no-cache' @@ -284,7 +284,7 @@ export const fixtureSuites: E2ETestFixtureSuite[] = [ fixtures: [ { // first request to ensure the cache is populated - path: 'dev/test-basic-openapi@b6e21206/getPost', + path: '@dev/test-basic-openapi@fc856666/getPost', request: { searchParams: { postId: 9 @@ -293,7 +293,7 @@ export const fixtureSuites: E2ETestFixtureSuite[] = [ }, { // second request should hit the cache - path: 'dev/test-basic-openapi@b6e21206/getPost?postId=9', + path: '@dev/test-basic-openapi@fc856666/getPost?postId=9', response: { headers: { 'cf-cache-status': 'HIT' @@ -302,7 +302,7 @@ export const fixtureSuites: E2ETestFixtureSuite[] = [ }, { // normalized request should also hit the cache - path: 'dev/test-basic-openapi@b6e21206/get_post?postId=9', + path: '@dev/test-basic-openapi@fc856666/get_post?postId=9', response: { headers: { 'cf-cache-status': 'HIT' @@ -318,7 +318,7 @@ export const fixtureSuites: E2ETestFixtureSuite[] = [ fixtures: [ { // first request to ensure the cache is populated - path: 'dev/test-basic-openapi@b6e21206/get_post', + path: '@dev/test-basic-openapi@fc856666/get_post', request: { method: 'POST', json: { @@ -328,7 +328,7 @@ export const fixtureSuites: E2ETestFixtureSuite[] = [ }, { // second request should hit the cache - path: 'dev/test-basic-openapi@b6e21206/get_post', + path: '@dev/test-basic-openapi@fc856666/get_post', request: { method: 'POST', json: { @@ -343,4 +343,19 @@ export const fixtureSuites: E2ETestFixtureSuite[] = [ } ] } + // { + // title: 'Basic MCP origin tool call success', + // compareResponseBodies: true, + // fixtures: [ + // { + // path: '@dev/test-basic-openapi@fc856666/get_post', + // request: { + // method: 'POST', + // json: { + // postId: 13 + // } + // } + // }, + // ] + // } ] diff --git a/apps/gateway/src/lib/resolve-origin-request.ts b/apps/gateway/src/lib/resolve-origin-request.ts index 0317040d..feb42db8 100644 --- a/apps/gateway/src/lib/resolve-origin-request.ts +++ b/apps/gateway/src/lib/resolve-origin-request.ts @@ -35,16 +35,13 @@ export async function resolveOriginRequest( const { method } = ctx.req const requestUrl = new URL(ctx.req.url) const { pathname } = requestUrl - const requestPathParts = pathname.split('/') - - // TODO: the isMCPRequest logic needs to be completely redone. - const isMCPRequest = requestPathParts[0] === 'mcp' - const requestPath = isMCPRequest - ? requestPathParts.slice(1).join('/') - : pathname - - const parsedToolIdentifier = parseToolIdentifier(requestPath) - assert(parsedToolIdentifier, 404, `Invalid tool identifier "${requestPath}"`) + const requestedToolIdentifier = pathname.replace(/^\//, '') + const parsedToolIdentifier = parseToolIdentifier(requestedToolIdentifier) + assert( + parsedToolIdentifier, + 404, + `Invalid tool identifier "${requestedToolIdentifier}"` + ) const { toolName } = parsedToolIdentifier const deployment = await getAdminDeployment( diff --git a/packages/cli/src/lib/resolve-deployment.ts b/packages/cli/src/lib/resolve-deployment.ts index 92cfc11f..aca49778 100644 --- a/packages/cli/src/lib/resolve-deployment.ts +++ b/packages/cli/src/lib/resolve-deployment.ts @@ -7,7 +7,7 @@ import { AuthStore } from './auth-store' export async function resolveDeployment({ client, deploymentIdentifier, - fuzzyDeploymentIdentifierVersion = 'latest', + fuzzyDeploymentIdentifierVersion, cwd, populate }: { @@ -27,7 +27,7 @@ export async function resolveDeployment({ // TODO: resolve deploymentIdentifier; config name may include namespace? // TODO: this needs work... - deploymentIdentifier = `${namespace}/${config.name}@${fuzzyDeploymentIdentifierVersion}` + deploymentIdentifier = `@${namespace}/${config.name}${fuzzyDeploymentIdentifierVersion ? `@${fuzzyDeploymentIdentifierVersion}` : ''}` } const deployment = await client.getDeploymentByIdentifier({ diff --git a/packages/hono/src/error-handler.ts b/packages/hono/src/error-handler.ts index 17bf476d..8f0b48bd 100644 --- a/packages/hono/src/error-handler.ts +++ b/packages/hono/src/error-handler.ts @@ -33,7 +33,7 @@ export function errorHandler( if (status >= 500) { logger.error(status, err) captureException(err) - } else if (isProd) { + } else { logger.warn(status, err) } 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 c7bc21d0..199c9342 100644 --- a/packages/platform/src/__snapshots__/load-agentic-config.test.ts.snap +++ b/packages/platform/src/__snapshots__/load-agentic-config.test.ts.snap @@ -1,5 +1,34 @@ // Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html +exports[`loadAgenticConfig > basic-mcp 1`] = ` +{ + "name": "test-basic-mcp", + "originAdapter": { + "location": "external", + "type": "mcp", + }, + "originUrl": "https://agentic-basic-mcp-test.onrender.com/stream", + "pricingIntervals": [ + "month", + ], + "pricingPlans": [ + { + "lineItems": [ + { + "amount": 0, + "slug": "base", + "usageType": "licensed", + }, + ], + "name": "Free", + "slug": "free", + }, + ], + "toolConfigs": [], + "version": undefined, +} +`; + exports[`loadAgenticConfig > basic-openapi 1`] = ` { "name": "test-basic-openapi", @@ -88,15 +117,15 @@ exports[`loadAgenticConfig > basic-raw-free-ts 1`] = ` } `; -exports[`loadAgenticConfig > invalid: invalid-name-0 1`] = `[Error: Invalid project name "Test Invalid Name 0". Must be lower kebab-case with no spaces between 2 and 64 characters. Example: "my-project" or "linkedin-resolver-23"]`; +exports[`loadAgenticConfig > invalid: invalid-name-0 1`] = `[Error: Invalid project name "Test Invalid Name 0". Must be ascii-only lower kebab-case with no spaces between 1 and 256 characters. For example: "my-project" or "linkedin-resolver-23"]`; -exports[`loadAgenticConfig > invalid: invalid-name-1 1`] = `[Error: Invalid project name "Test-Invalid-Name-1". Must be lower kebab-case with no spaces between 2 and 64 characters. Example: "my-project" or "linkedin-resolver-23"]`; +exports[`loadAgenticConfig > invalid: invalid-name-1 1`] = `[Error: Invalid project name "Test-Invalid-Name-1". Must be ascii-only lower kebab-case with no spaces between 1 and 256 characters. For example: "my-project" or "linkedin-resolver-23"]`; -exports[`loadAgenticConfig > invalid: invalid-name-2 1`] = `[Error: Invalid project name "test_invalid_name_2". Must be lower kebab-case with no spaces between 2 and 64 characters. Example: "my-project" or "linkedin-resolver-23"]`; +exports[`loadAgenticConfig > invalid: invalid-name-2 1`] = `[Error: Invalid project name "test_invalid_name_2". Must be ascii-only lower kebab-case with no spaces between 1 and 256 characters. For example: "my-project" or "linkedin-resolver-23"]`; exports[`loadAgenticConfig > invalid: invalid-name-3 1`] = `[ZodValidationError: Validation error: Required at "name"]`; -exports[`loadAgenticConfig > invalid: invalid-name-4 1`] = `[Error: Invalid project name "@foo/bar". Must be lower kebab-case with no spaces between 2 and 64 characters. Example: "my-project" or "linkedin-resolver-23"]`; +exports[`loadAgenticConfig > invalid: invalid-name-4 1`] = `[Error: Invalid project name "@foo/bar". Must be ascii-only lower kebab-case with no spaces between 1 and 256 characters. For example: "my-project" or "linkedin-resolver-23"]`; exports[`loadAgenticConfig > invalid: invalid-origin-url-0 1`] = `[Error: Invalid originUrl: must be a valid https URL]`; diff --git a/packages/platform/src/load-agentic-config.test.ts b/packages/platform/src/load-agentic-config.test.ts index cc8e8133..42078c35 100644 --- a/packages/platform/src/load-agentic-config.test.ts +++ b/packages/platform/src/load-agentic-config.test.ts @@ -13,7 +13,8 @@ const fixtures = [ 'pricing-3-plans', 'pricing-monthly-annual', 'pricing-custom-0', - 'basic-openapi' + 'basic-openapi', + 'basic-mcp' ] const invalidFixtures = [ diff --git a/packages/platform/src/resolve-metadata.ts b/packages/platform/src/resolve-metadata.ts index 7bb2b42a..86eac6ab 100644 --- a/packages/platform/src/resolve-metadata.ts +++ b/packages/platform/src/resolve-metadata.ts @@ -12,7 +12,7 @@ export function resolveMetadata({ > { assert( isValidProjectName(name), - `Invalid project name "${name}". Must be lower kebab-case with no spaces between 2 and 64 characters. Example: "my-project" or "linkedin-resolver-23"` + `Invalid project name "${name}". Must be ascii-only lower kebab-case with no spaces between 1 and 256 characters. For example: "my-project" or "linkedin-resolver-23"` ) if (version) { diff --git a/readme.md b/readme.md index 4598130f..becfef04 100644 --- a/readme.md +++ b/readme.md @@ -37,6 +37,9 @@ - how to handle binary bodies and responses? - add requestId to all JSON error responses - add support for `immutable` in `toolConfigs` +- mcp origin servers + - ignore sse for now + - only support [streamable http](https://modelcontextprotocol.io/specification/2025-03-26/basic/transports#streamable-http) like smithery does ## TODO Post-MVP