From e5ce2e24add52015d210a832ba889e3cd7dc979e Mon Sep 17 00:00:00 2001 From: Jonathan Norris Date: Wed, 1 Oct 2025 11:52:02 -0400 Subject: [PATCH 1/2] fix: ensure v2ApiClient uses shared axios instance for MCP headers --- src/api/apiClient.ts | 6 ++- .../__snapshots__/update.test.ts.snap | 42 +++++++++---------- src/mcp/utils/api.test.ts | 18 +++++++- 3 files changed, 43 insertions(+), 23 deletions(-) diff --git a/src/api/apiClient.ts b/src/api/apiClient.ts index 8b831554..a1f32b19 100644 --- a/src/api/apiClient.ts +++ b/src/api/apiClient.ts @@ -116,4 +116,8 @@ const apiClient: ApiClientType = _createApiClient(BASE_URL, { export { apiClient } export default apiClient -export const v2ApiClient = createV2ApiClient(BASE_URL) +// Create v2 API client using the same shared axiosClient instance to preserve MCP headers +export const v2ApiClient = createV2ApiClient(BASE_URL, { + axiosInstance: axiosClient, + validate: 'request', +}) diff --git a/src/commands/features/__snapshots__/update.test.ts.snap b/src/commands/features/__snapshots__/update.test.ts.snap index e5fb0b13..044055dc 100644 --- a/src/commands/features/__snapshots__/update.test.ts.snap +++ b/src/commands/features/__snapshots__/update.test.ts.snap @@ -5,50 +5,50 @@ exports[`features update > accepts flags and prompts for missing fields 1`] = ` 🤖 Current values: 🤖 { + "name": "Feature Name", + "key": "feature-key", "_id": "id", "_project": "string", "source": "api", - "name": "Feature Name", - "key": "feature-key", "_createdBy": "string", "createdAt": "2019-08-24T14:15:22Z", "updatedAt": "2019-08-24T14:15:22Z", "variations": [], - "controlVariation": "variation_id", "variables": [], "tags": [], "ldLink": "string", "readonly": true, - "settings": {}, "sdkVisibility": { "mobile": true, "client": true, "server": true - } + }, + "settings": {}, + "controlVariation": "variation_id" } { + "name": "Feature Name", + "key": "feature-key", "_id": "id", "_project": "string", "source": "api", - "name": "Feature Name", - "key": "feature-key", "_createdBy": "string", "createdAt": "2019-08-24T14:15:22Z", "updatedAt": "2019-08-24T14:15:22Z", "variations": [], - "controlVariation": "variation_id", "variables": [], "tags": [], "ldLink": "string", "readonly": true, - "settings": {}, "sdkVisibility": { "mobile": true, "client": true, "server": true - } + }, + "settings": {}, + "controlVariation": "variation_id" } " `; @@ -58,26 +58,26 @@ exports[`features update > updates a feature after prompting for all fields 1`] 🤖 Current values: 🤖 { + "name": "Feature Name", + "key": "feature-key", "_id": "id", "_project": "string", "source": "api", - "name": "Feature Name", - "key": "feature-key", "_createdBy": "string", "createdAt": "2019-08-24T14:15:22Z", "updatedAt": "2019-08-24T14:15:22Z", "variations": [], - "controlVariation": "variation_id", "variables": [], "tags": [], "ldLink": "string", "readonly": true, - "settings": {}, "sdkVisibility": { "mobile": true, "client": true, "server": true - } + }, + "settings": {}, + "controlVariation": "variation_id" } @@ -85,31 +85,31 @@ exports[`features update > updates a feature after prompting for all fields 1`] 🤖 No existing Variations. ---------------------------------------- { + "name": "Feature Name", + "key": "feature-key", "_id": "id", "_project": "string", "source": "api", - "name": "Feature Name", - "key": "feature-key", "_createdBy": "string", "createdAt": "2019-08-24T14:15:22Z", "updatedAt": "2019-08-24T14:15:22Z", "variations": [], - "controlVariation": "variation_id", "variables": [], "tags": [], "ldLink": "string", "readonly": true, - "settings": {}, "sdkVisibility": { "mobile": true, "client": true, "server": true - } + }, + "settings": {}, + "controlVariation": "variation_id" } " `; exports[`features update > updates a feature in headless mode 1`] = ` -"{"_id":"id","_project":"string","source":"api","name":"Feature Name","key":"feature-key","_createdBy":"string","createdAt":"2019-08-24T14:15:22Z","updatedAt":"2019-08-24T14:15:22Z","variations":[],"controlVariation":"variation_id","variables":[],"tags":[],"ldLink":"string","readonly":true,"settings":{},"sdkVisibility":{"mobile":true,"client":true,"server":true}} +"{"name":"Feature Name","key":"feature-key","_id":"id","_project":"string","source":"api","_createdBy":"string","createdAt":"2019-08-24T14:15:22Z","updatedAt":"2019-08-24T14:15:22Z","variations":[],"variables":[],"tags":[],"ldLink":"string","readonly":true,"sdkVisibility":{"mobile":true,"client":true,"server":true},"settings":{},"controlVariation":"variation_id"} " `; diff --git a/src/mcp/utils/api.test.ts b/src/mcp/utils/api.test.ts index 89a27986..c8397028 100644 --- a/src/mcp/utils/api.test.ts +++ b/src/mcp/utils/api.test.ts @@ -4,7 +4,7 @@ import * as assert from 'assert' import { DevCycleApiClient, handleZodiosValidationErrors } from './api' import { DevCycleAuth } from './auth' import { setMCPToolCommand } from './headers' -import { axiosClient } from '../../api/apiClient' +import { axiosClient, v2ApiClient } from '../../api/apiClient' describe('DevCycleApiClient', () => { let apiClient: DevCycleApiClient @@ -185,5 +185,21 @@ describe('Header Management', () => { expect(meta.command).to.equal('list_features') expect(meta.caller).to.equal('mcp') }) + + it('should ensure v2ApiClient uses shared axiosClient instance with MCP headers', () => { + // Set MCP headers on the shared axiosClient + setMCPToolCommand('create_feature') + + // Verify that the v2ApiClient has access to the same headers + // This works because v2ApiClient should be using the shared axiosClient instance + const headers = axiosClient.defaults.headers.common as any + expect(headers['dvc-referrer']).to.equal('mcp') + const meta = JSON.parse(headers['dvc-referrer-metadata']) + expect(meta.command).to.equal('create_feature') + expect(meta.caller).to.equal('mcp') + + // Verify v2ApiClient exists and is properly configured + expect(v2ApiClient).to.exist + }) }) }) From 0dec95ad1df521814c2fe342cb8cb50150821f9f Mon Sep 17 00:00:00 2001 From: Jonathan Norris Date: Wed, 1 Oct 2025 15:51:09 -0400 Subject: [PATCH 2/2] fix: upgrade @modelcontextprotocol/sdk to 1.18.1 for type compatibility --- mcp-worker/src/index.ts | 9 +++++---- package.json | 2 +- yarn.lock | 22 +--------------------- 3 files changed, 7 insertions(+), 26 deletions(-) diff --git a/mcp-worker/src/index.ts b/mcp-worker/src/index.ts index d1c99675..8250401e 100644 --- a/mcp-worker/src/index.ts +++ b/mcp-worker/src/index.ts @@ -1,4 +1,4 @@ -import OAuthProvider from '@cloudflare/workers-oauth-provider' +import OAuthProvider, { OAuthHelpers } from '@cloudflare/workers-oauth-provider' import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js' import type { ToolAnnotations } from '@modelcontextprotocol/sdk/types.js' import type { ZodRawShape } from 'zod' @@ -54,6 +54,9 @@ export class DevCycleMCP extends McpAgent { WorkerApiClient.initializeMCPHeaders(this.version) // Initialize the Worker-specific API client with OAuth tokens and state management + if (!this.props) { + throw new Error('User props not available') + } this.apiClient = new WorkerApiClient( this.props, this.env, @@ -158,12 +161,10 @@ export default { // Create OAuth provider with env access const provider = new OAuthProvider({ apiHandlers: { - // @ts-expect-error - type errors with the OAuthProvider '/sse': DevCycleMCP.serveSSE('/sse'), - // @ts-expect-error - type errors with the OAuthProvider '/mcp': DevCycleMCP.serve('/mcp'), }, - // @ts-expect-error - type erorrs with the OAuthProvider + // @ts-expect-error - Hono's fetch signature is compatible but TypeScript can't verify exact type match defaultHandler: app, authorizeEndpoint: '/oauth/authorize', tokenEndpoint: '/oauth/token', diff --git a/package.json b/package.json index e7736b10..802f465e 100644 --- a/package.json +++ b/package.json @@ -41,7 +41,7 @@ }, "dependencies": { "@babel/parser": "^7.28.0", - "@modelcontextprotocol/sdk": "^1.17.1", + "@modelcontextprotocol/sdk": "^1.18.1", "@oclif/core": "^2.16.0", "@oclif/plugin-autocomplete": "^2.3.10", "@oclif/plugin-help": "^6.2.27", diff --git a/yarn.lock b/yarn.lock index 8bc07442..dbc11505 100644 --- a/yarn.lock +++ b/yarn.lock @@ -604,7 +604,7 @@ __metadata: "@babel/traverse": "npm:^7.28.0" "@babel/types": "npm:^7.28.0" "@eslint/js": "npm:^9.18.0" - "@modelcontextprotocol/sdk": "npm:^1.17.1" + "@modelcontextprotocol/sdk": "npm:^1.18.1" "@oclif/core": "npm:^2.16.0" "@oclif/plugin-autocomplete": "npm:^2.3.10" "@oclif/plugin-help": "npm:^6.2.27" @@ -1799,26 +1799,6 @@ __metadata: languageName: node linkType: hard -"@modelcontextprotocol/sdk@npm:^1.17.1": - version: 1.17.1 - resolution: "@modelcontextprotocol/sdk@npm:1.17.1" - dependencies: - ajv: "npm:^6.12.6" - content-type: "npm:^1.0.5" - cors: "npm:^2.8.5" - cross-spawn: "npm:^7.0.5" - eventsource: "npm:^3.0.2" - eventsource-parser: "npm:^3.0.0" - express: "npm:^5.0.1" - express-rate-limit: "npm:^7.5.0" - pkce-challenge: "npm:^5.0.0" - raw-body: "npm:^3.0.0" - zod: "npm:^3.23.8" - zod-to-json-schema: "npm:^3.24.1" - checksum: 10c0/bddee1c4a90adb2ee3f89f5598f0499841b1ad8b4d9a52b2b0afac3009918570d72240588a17178e319bdfbe70aced190f66b25e14f0a0645eacaf4776d4c15a - languageName: node - linkType: hard - "@modelcontextprotocol/sdk@npm:^1.18.1": version: 1.18.1 resolution: "@modelcontextprotocol/sdk@npm:1.18.1"