diff --git a/.changeset/fix-get-env-key-parameter.md b/.changeset/fix-get-env-key-parameter.md new file mode 100644 index 0000000000..c53dccdeb3 --- /dev/null +++ b/.changeset/fix-get-env-key-parameter.md @@ -0,0 +1,5 @@ +--- +"@modelcontextprotocol/server-everything": patch +--- + +Fix security issue in get-env tool: require a specific key parameter instead of returning the entire process.env object unfiltered. The tool now accepts a required `key` argument and returns only the value of that specific environment variable, preventing accidental exposure of sensitive data such as API keys, tokens, and credentials. diff --git a/src/everything/__tests__/tools.test.ts b/src/everything/__tests__/tools.test.ts index dbe463b2a5..8c02f8ee53 100644 --- a/src/everything/__tests__/tools.test.ts +++ b/src/everything/__tests__/tools.test.ts @@ -151,31 +151,33 @@ describe('Tools', () => { }); describe('get-env', () => { - it('should return all environment variables as JSON', async () => { + it('should return the value of a specific environment variable', async () => { const { mockServer, handlers } = createMockServer(); registerGetEnvTool(mockServer); const handler = handlers.get('get-env')!; process.env.TEST_VAR_EVERYTHING = 'test_value'; - const result = await handler({}); + const result = await handler({ key: 'TEST_VAR_EVERYTHING' }); expect(result.content).toHaveLength(1); expect(result.content[0].type).toBe('text'); - - const envJson = JSON.parse(result.content[0].text); - expect(envJson.TEST_VAR_EVERYTHING).toBe('test_value'); + expect(result.content[0].text).toBe('test_value'); delete process.env.TEST_VAR_EVERYTHING; }); - it('should return valid JSON', async () => { + it('should return a message when the key does not exist', async () => { const { mockServer, handlers } = createMockServer(); registerGetEnvTool(mockServer); const handler = handlers.get('get-env')!; - const result = await handler({}); + const result = await handler({ key: 'NONEXISTENT_VAR_12345' }); - expect(() => JSON.parse(result.content[0].text)).not.toThrow(); + expect(result.content).toHaveLength(1); + expect(result.content[0].type).toBe('text'); + expect(result.content[0].text).toBe( + 'Environment variable "NONEXISTENT_VAR_12345" is not set.' + ); }); }); diff --git a/src/everything/tools/get-env.ts b/src/everything/tools/get-env.ts index 0adbf5a14d..49995dd390 100644 --- a/src/everything/tools/get-env.ts +++ b/src/everything/tools/get-env.ts @@ -1,33 +1,44 @@ import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js"; import { CallToolResult } from "@modelcontextprotocol/sdk/types.js"; +import { z } from "zod"; + +// Tool input schema +const GetEnvSchema = z.object({ + key: z.string().describe("Specific environment variable name"), +}); // Tool configuration const name = "get-env"; const config = { - title: "Print Environment Tool", + title: "Get Environment Variable", description: - "Returns all environment variables, helpful for debugging MCP server configuration", - inputSchema: {}, + 'Returns the value of a specific environment variable. Pass the variable name via the "key" argument.', + inputSchema: GetEnvSchema, }; /** * Registers the 'get-env' tool. * - * The registered tool Retrieves and returns the environment variables - * of the current process as a JSON-formatted string encapsulated in a text response. + * The registered tool retrieves and returns the value of a specific + * environment variable specified by the 'key' argument. * * @param {McpServer} server - The McpServer instance where the tool will be registered. * @returns {void} */ export const registerGetEnvTool = (server: McpServer) => { server.registerTool(name, config, async (args): Promise => { + const { key } = GetEnvSchema.parse(args); + const value = process.env[key]; + + // Return a clear message if the key doesn't exist rather than exposing the full env + if (value === undefined) { + return { + content: [{ type: "text", text: `Environment variable "${key}" is not set.` }], + }; + } + return { - content: [ - { - type: "text", - text: JSON.stringify(process.env, null, 2), - }, - ], + content: [{ type: "text", text: value }], }; }); };