Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion src/api/apiClient.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ export const setDVCReferrer = (
version: string,
caller = 'cli',
): void => {
axiosClient.defaults.headers.common['dvc-referrer'] = 'cli'
axiosClient.defaults.headers.common['dvc-referrer'] = caller

// Ensure we have valid values before stringifying
const metadata = {
Expand Down
9 changes: 8 additions & 1 deletion src/mcp/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js'
import { DevCycleMCPServer } from './server'
import { readFileSync } from 'fs'
import { join } from 'path'
import { setMCPHeaders } from './utils/headers'

// Get version for MCP server
function getVersion(): string {
Expand Down Expand Up @@ -46,10 +47,16 @@ if (args.includes('--help') || args.includes('-h')) {
}

async function main() {
const version = getVersion()

// Set up MCP-specific headers for all API requests
// This ensures that requests from the MCP server are properly identified
setMCPHeaders(version)

const server = new Server(
{
name: 'devcycle',
version: getVersion(),
version,
},
{
capabilities: {
Expand Down
4 changes: 4 additions & 0 deletions src/mcp/utils/api.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { DevCycleAuth } from './auth'
import { setMCPToolCommand } from './headers'

function getErrorMessage(error: unknown): string {
if (error instanceof Error && error.message) {
Expand Down Expand Up @@ -49,6 +50,9 @@ export class DevCycleApiClient {
this.auth.requireProject()
}

// Set the specific MCP tool command in headers before making API calls
setMCPToolCommand(operationName)

const authToken = this.auth.getAuthToken()
const projectKey = requiresProject ? this.auth.getProjectKey() : ''

Expand Down
29 changes: 29 additions & 0 deletions src/mcp/utils/headers.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
import { setDVCReferrer } from '../../api/apiClient'

// Store the version for reuse in tool commands
let mcpVersion: string = 'unknown'

/**
* Sets up MCP-specific headers for all API requests
* This ensures that API calls made from the MCP server are properly identified
* and can be tracked separately from CLI commands
*/
export function setMCPHeaders(version: string): void {
// Store version for later use in tool commands
mcpVersion = version

// Set the referrer to identify this as an MCP request
// Command will be set dynamically for each tool call
// Caller is 'mcp' to distinguish from 'cli' and other callers
setDVCReferrer('mcp', version, 'mcp')
Copy link
Member

Choose a reason for hiding this comment

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

mcp local?

Copy link
Member Author

Choose a reason for hiding this comment

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

I'm not going to worry about that distinction until we figure out how we are going to deploy this.

}

/**
* Updates the command in the headers for a specific MCP tool call
* This allows tracking of individual MCP operations (e.g., "list_features", "create_project")
* @param toolName - The name of the MCP tool being called
*/
export function setMCPToolCommand(toolName: string): void {
// Update the command to be the tool name, keeping version and caller the same
setDVCReferrer(toolName, mcpVersion, 'mcp')
Copy link
Member

Choose a reason for hiding this comment

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

mcp local instead?

}