Skip to content

Commit d52b173

Browse files
chore(internal): support custom-instructions-path flag in MCP servers
1 parent 492d238 commit d52b173

File tree

5 files changed

+47
-8
lines changed

5 files changed

+47
-8
lines changed

packages/mcp-server/src/http.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,8 @@ const newServer = async ({
2323
res: express.Response;
2424
}): Promise<McpServer | null> => {
2525
const stainlessApiKey = getStainlessApiKey(req, mcpOptions);
26-
const server = await newMcpServer(stainlessApiKey);
26+
const customInstructionsPath = mcpOptions.customInstructionsPath;
27+
const server = await newMcpServer({ stainlessApiKey, customInstructionsPath });
2728

2829
const authOptions = parseClientAuthHeaders(req, false);
2930

packages/mcp-server/src/instructions.ts

Lines changed: 27 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
22

3+
import fs from 'fs/promises';
34
import { readEnv } from './util';
45
import { getLogger } from './logger';
56

@@ -12,9 +13,15 @@ interface InstructionsCacheEntry {
1213

1314
const instructionsCache = new Map<string, InstructionsCacheEntry>();
1415

15-
export async function getInstructions(stainlessApiKey: string | undefined): Promise<string> {
16+
export async function getInstructions({
17+
stainlessApiKey,
18+
customInstructionsPath,
19+
}: {
20+
stainlessApiKey?: string | undefined;
21+
customInstructionsPath?: string | undefined;
22+
}): Promise<string> {
1623
const now = Date.now();
17-
const cacheKey = stainlessApiKey ?? '';
24+
const cacheKey = customInstructionsPath ?? stainlessApiKey ?? '';
1825
const cached = instructionsCache.get(cacheKey);
1926

2027
if (cached && now - cached.fetchedAt <= INSTRUCTIONS_CACHE_TTL_MS) {
@@ -28,12 +35,28 @@ export async function getInstructions(stainlessApiKey: string | undefined): Prom
2835
}
2936
}
3037

31-
const fetchedInstructions = await fetchLatestInstructions(stainlessApiKey);
38+
let fetchedInstructions: string;
39+
40+
if (customInstructionsPath) {
41+
fetchedInstructions = await fetchLatestInstructionsFromFile(customInstructionsPath);
42+
} else {
43+
fetchedInstructions = await fetchLatestInstructionsFromApi(stainlessApiKey);
44+
}
45+
3246
instructionsCache.set(cacheKey, { fetchedInstructions, fetchedAt: now });
3347
return fetchedInstructions;
3448
}
3549

36-
async function fetchLatestInstructions(stainlessApiKey: string | undefined): Promise<string> {
50+
async function fetchLatestInstructionsFromFile(path: string): Promise<string> {
51+
try {
52+
return await fs.readFile(path, 'utf-8');
53+
} catch (error) {
54+
getLogger().error({ error, path }, 'Error fetching instructions from file');
55+
throw error;
56+
}
57+
}
58+
59+
async function fetchLatestInstructionsFromApi(stainlessApiKey: string | undefined): Promise<string> {
3760
// Setting the stainless API key is optional, but may be required
3861
// to authenticate requests to the Stainless API.
3962
const response = await fetch(

packages/mcp-server/src/options.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ export type McpOptions = {
2222
codeAllowedMethods?: string[] | undefined;
2323
codeBlockedMethods?: string[] | undefined;
2424
codeExecutionMode: McpCodeExecutionMode;
25+
customInstructionsPath?: string | undefined;
2526
};
2627

2728
export type McpCodeExecutionMode = 'stainless-sandbox' | 'local';
@@ -52,6 +53,10 @@ export function parseCLIOptions(): CLIOptions {
5253
description:
5354
"Where to run code execution in code tool; 'stainless-sandbox' will execute code in Stainless-hosted sandboxes whereas 'local' will execute code locally on the MCP server machine.",
5455
})
56+
.option('custom-instructions-path', {
57+
type: 'string',
58+
description: 'Path to custom instructions for the MCP server',
59+
})
5560
.option('debug', { type: 'boolean', description: 'Enable debug logging' })
5661
.option('log-format', {
5762
type: 'string',
@@ -117,6 +122,7 @@ export function parseCLIOptions(): CLIOptions {
117122
codeAllowedMethods: argv.codeAllowedMethods,
118123
codeBlockedMethods: argv.codeBlockedMethods,
119124
codeExecutionMode: argv.codeExecutionMode as McpCodeExecutionMode,
125+
customInstructionsPath: argv.customInstructionsPath,
120126
transport,
121127
logFormat,
122128
port: argv.port,

packages/mcp-server/src/server.ts

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,14 +16,20 @@ import { McpOptions } from './options';
1616
import { blockedMethodsForCodeTool } from './methods';
1717
import { HandlerFunction, McpRequestContext, ToolCallResult, McpTool } from './types';
1818

19-
export const newMcpServer = async (stainlessApiKey: string | undefined) =>
19+
export const newMcpServer = async ({
20+
stainlessApiKey,
21+
customInstructionsPath,
22+
}: {
23+
stainlessApiKey?: string | undefined;
24+
customInstructionsPath?: string | undefined;
25+
}) =>
2026
new McpServer(
2127
{
2228
name: 'brand_dev_api',
2329
version: '0.31.0',
2430
},
2531
{
26-
instructions: await getInstructions(stainlessApiKey),
32+
instructions: await getInstructions({ stainlessApiKey, customInstructionsPath }),
2733
capabilities: { tools: {}, logging: {} },
2834
},
2935
);

packages/mcp-server/src/stdio.ts

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,10 @@ import { initMcpServer, newMcpServer } from './server';
44
import { getLogger } from './logger';
55

66
export const launchStdioServer = async (mcpOptions: McpOptions) => {
7-
const server = await newMcpServer(mcpOptions.stainlessApiKey);
7+
const server = await newMcpServer({
8+
stainlessApiKey: mcpOptions.stainlessApiKey,
9+
customInstructionsPath: mcpOptions.customInstructionsPath,
10+
});
811

912
await initMcpServer({ server, mcpOptions, stainlessApiKey: mcpOptions.stainlessApiKey });
1013

0 commit comments

Comments
 (0)