From b82f67e7915df3a73690deb146355ce2c14d2628 Mon Sep 17 00:00:00 2001 From: "Dr. Dominik Jain" Date: Tue, 17 Mar 2026 18:48:06 +0100 Subject: [PATCH] :sparkles: Reduce instructions transferred at MCP connection to a minimum (#8649) * :sparkles: Reduce instructions transferred at MCP connection to a minimum Force on-demand loading of the 'Penpot High-Level Overview', which was previously transferred in the MCP server's instructions. This greatly reduces the number of tokens for users who will not actually interact with Penpot, allowing the MCP server to remain enabled for such users without wasting too many tokens. Resolves #8647 * :paperclip: Update Serena project --- mcp/.serena/project.yml | 30 ++++++++++++++++--- mcp/packages/server/data/base_instructions.md | 2 ++ .../server/src/ConfigurationLoader.ts | 23 +++++++++----- mcp/packages/server/src/PenpotMcpServer.ts | 17 +++++++---- .../server/src/tools/HighLevelOverviewTool.ts | 2 +- 5 files changed, 56 insertions(+), 18 deletions(-) create mode 100644 mcp/packages/server/data/base_instructions.md diff --git a/mcp/.serena/project.yml b/mcp/.serena/project.yml index c9ed0f7330..f0c29eaaf2 100644 --- a/mcp/.serena/project.yml +++ b/mcp/.serena/project.yml @@ -19,7 +19,7 @@ read_only: false # list of tool names to exclude. We recommend not excluding any tools, see the readme for more details. # Below is the complete list of tools for convenience. -# To make sure you have the latest list of tools, and to view their descriptions, +# To make sure you have the latest list of tools, and to view their descriptions, # execute `uv run scripts/print_tool_overview.py`. # # * `activate_project`: Activates a project by name. @@ -62,15 +62,15 @@ excluded_tools: [] # (contrary to the memories, which are loaded on demand). initial_prompt: | IMPORTANT: You use an idiomatic, object-oriented style. - In particular, this implies that, for any non-trivial interfaces, you use interfaces that expect explicitly typed abstractions + In particular, this implies that, for any non-trivial interfaces, you use interfaces that expect explicitly typed abstractions rather than mere functions (i.e. use the strategy pattern, for example). - Comments: + Comments: When describing parameters, methods/functions and classes, you use a precise style, where the initial (elliptical) phrase clearly defines *what* it is. Any details then follow in subsequent sentences. When describing what blocks of code do, you also use an elliptical style and start with a lower-case letter unless - the comment is a lengthy explanation with at least two sentences (in which case you start with a capital letter, as is + the comment is a lengthy explanation with at least two sentences (in which case you start with a capital letter, as is required for sentences). # the name by which the project can be referenced within Serena project_name: "penpot-mcp" @@ -128,3 +128,25 @@ encoding: utf-8 # Note that when using the JetBrains backend, language servers are not used and this list is correspondingly ignored. languages: - typescript + +# time budget (seconds) per tool call for the retrieval of additional symbol information +# such as docstrings or parameter information. +# This overrides the corresponding setting in the global configuration; see the documentation there. +# If null or missing, use the setting from the global configuration. +symbol_info_budget: + +# The language backend to use for this project. +# If not set, the global setting from serena_config.yml is used. +# Valid values: LSP, JetBrains +# Note: the backend is fixed at startup. If a project with a different backend +# is activated post-init, an error will be returned. +language_backend: + +# line ending convention to use when writing source files. +# Possible values: unset (use global setting), "lf", "crlf", or "native" (platform default) +# This does not affect Serena's own files (e.g. memories and configuration files), which always use native line endings. +line_ending: + +# list of regex patterns which, when matched, mark a memory entry as read‑only. +# Extends the list from the global configuration, merging the two lists. +read_only_memory_patterns: [] diff --git a/mcp/packages/server/data/base_instructions.md b/mcp/packages/server/data/base_instructions.md new file mode 100644 index 0000000000..10245a2b45 --- /dev/null +++ b/mcp/packages/server/data/base_instructions.md @@ -0,0 +1,2 @@ +You have access to Penpot tools in order to interact with Penpot designs. +Before working with these tools, be sure to read the 'Penpot High-Level Overview' via the `high_level_overview` tool. diff --git a/mcp/packages/server/src/ConfigurationLoader.ts b/mcp/packages/server/src/ConfigurationLoader.ts index 390522ff24..2b4b11288e 100644 --- a/mcp/packages/server/src/ConfigurationLoader.ts +++ b/mcp/packages/server/src/ConfigurationLoader.ts @@ -4,15 +4,12 @@ import { createLogger } from "./logger.js"; /** * Configuration loader for prompts and server settings. - * - * Handles loading and parsing of YAML configuration files, - * providing type-safe access to configuration values with - * appropriate fallbacks for missing files or values. */ export class ConfigurationLoader { private readonly logger = createLogger("ConfigurationLoader"); private readonly baseDir: string; - private initialInstructions: string; + private readonly initialInstructions: string; + private readonly baseInstructions: string; /** * Creates a new configuration loader instance. @@ -22,6 +19,7 @@ export class ConfigurationLoader { constructor(baseDir: string) { this.baseDir = baseDir; this.initialInstructions = this.loadFileContent(join(this.baseDir, "data", "initial_instructions.md")); + this.baseInstructions = this.loadFileContent(join(this.baseDir, "data", "base_instructions.md")); } private loadFileContent(filePath: string): string { @@ -32,11 +30,22 @@ export class ConfigurationLoader { } /** - * Gets the initial instructions for the MCP server. + * Gets the initial instructions for the MCP server corresponding to the + * 'Penpot High-Level Overview' * - * @returns The initial instructions string, or undefined if not configured + * @returns The initial instructions string */ public getInitialInstructions(): string { return this.initialInstructions; } + + /** + * Gets the base instructions which shall be provided to clients when connecting to + * the MCP server + * + * @returns The initial instructions string + */ + public getBaseInstructions(): string { + return this.baseInstructions; + } } diff --git a/mcp/packages/server/src/PenpotMcpServer.ts b/mcp/packages/server/src/PenpotMcpServer.ts index 2c4a2cc792..4cc08e43b3 100644 --- a/mcp/packages/server/src/PenpotMcpServer.ts +++ b/mcp/packages/server/src/PenpotMcpServer.ts @@ -56,7 +56,8 @@ export class PenpotMcpServer { public readonly pluginBridge: PluginBridge; private readonly replServer: ReplServer; private apiDocs: ApiDocs; - private initialInstructions: string; + private readonly penpotHighLevelOverview: string; + private readonly connectionInstructions: string; /** * Manages session-specific context, particularly user tokens for each request. @@ -82,10 +83,11 @@ export class PenpotMcpServer { this.configLoader = new ConfigurationLoader(process.cwd()); this.apiDocs = new ApiDocs(); - // prepare initial instructions + // prepare instructions let instructions = this.configLoader.getInitialInstructions(); instructions = instructions.replace("$api_types", this.apiDocs.getTypeNames().join(", ")); - this.initialInstructions = instructions; + this.penpotHighLevelOverview = instructions; + this.connectionInstructions = this.configLoader.getBaseInstructions(); this.tools = this.initTools(); @@ -124,8 +126,11 @@ export class PenpotMcpServer { return !this.isRemoteMode(); } - public getInitialInstructions(): string { - return this.initialInstructions; + /** + * Retrieves the high-level overview instructions explaining core Penpot usage. + */ + public getHighLevelOverviewInstructions(): string { + return this.penpotHighLevelOverview; } /** @@ -163,7 +168,7 @@ export class PenpotMcpServer { private createMcpServer(): McpServer { const server = new McpServer( { name: "penpot", version: "1.0.0" }, - { instructions: this.getInitialInstructions() } + { instructions: this.connectionInstructions } ); for (const tool of this.tools) { diff --git a/mcp/packages/server/src/tools/HighLevelOverviewTool.ts b/mcp/packages/server/src/tools/HighLevelOverviewTool.ts index ada8829771..b16edcb68b 100644 --- a/mcp/packages/server/src/tools/HighLevelOverviewTool.ts +++ b/mcp/packages/server/src/tools/HighLevelOverviewTool.ts @@ -21,6 +21,6 @@ export class HighLevelOverviewTool extends Tool { } protected async executeCore(args: EmptyToolArgs): Promise { - return new TextResponse(this.mcpServer.getInitialInstructions()); + return new TextResponse(this.mcpServer.getHighLevelOverviewInstructions()); } }