Repository navigation
Conversation
The query and database-change skills taught paths an agent should not take. query listed databases across the whole workspace and never named query_database. database-change had the agent create the rollout itself and add an engine field that Sheet does not have. get_skill served only these two, so it goes with them. Static server instructions take over the routing: which tool to use for reads, schemas and changes, what query_database runs under Read-write, and where a refused call goes. propose_database_change's description now states its single-database limit instead of pointing at the deleted skill. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
query_database sends the data source selectDataSource picks, which prefers a read-only one, and SQLService/Query keeps an explicit data source. On an instance with a read-only data source a write through query_database fails even under Read-write, so the instructions now say so and route those changes to propose_database_change. The single-database sentence now comes from one constant used by both the instructions and propose_database_change's description. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
zchpeter
reviewed
Oct 8, 2026
| - Change a database: propose_database_change, the easiest way into the governed workflow. It creates the plan and the issue and runs the plan checks; approval and rollout follow the project's policy. ` + singleDatabaseLimit + ` | ||
| - Anything else: search_api to find the operation and its request schema, then call_api. | ||
|
|
||
| When the workspace's MCP access policy is Read-write, query_database can also run DML and DDL. They take effect at once, without an issue or approval, as far as the engine and the user's permissions allow. On an instance with a read-only data source, query_database runs every statement through that data source, so make changes there with propose_database_change. Use propose_database_change for any change that should be reviewed. |
Collaborator
There was a problem hiding this comment.
for security purpose, let's initiate an AskUserQuestion explaining that a DDL/DML will be executed directly without approval and ask the user for permission to proceed.
DDL/DML could be very dangerous operation and in this case it's better to ask for permission - just like if we allow claude to bypass permission, when it tries to run rm claude will always ask first
After the change, let's attach a screenshot of this AskUserQuestion here
This branch has not been deployed
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Ships in the same release as #21551, which makes
query_database,get_schemaandpropose_database_changework for users whose access comes only from project roles. Thequeryskill removed here was their only path until then.This removes the MCP server's two embedded skills,
queryanddatabase-change, and theget_skilltool that served them. It adds static server instructions that route an agent to the right tool.The skills taught the wrong path:
query.md:30lists databases across the whole workspace, and the skill never mentionsquery_database. It also saysdataSourceIdis required (query.md:54).SQLService/Querypicks a data source when the request has none.database-change.md:119tells the agent to create the rollout itself, right after it creates the issue.database-change.md:143tells the agent to add anenginefield to the sheet.Sheethas onlyname,contentandcontent_size.get_skillserved only these two skills, so it goes too. The package'sAGENTS.mddocumented only how to write skills, so it goes with itsCLAUDE.mdimport.Server instructions
The server sent no instructions before. Now
initializereturns a short, static text. It says:query_databasefor reads,get_schemafor schemas,propose_database_changefor changes, andsearch_apithencall_apifor anything else;propose_database_changechanges one database per call;query_databasecan also run DML and DDL, which take effect at once, without an issue or approval;query_databaseruns every statement through that data source, so changes there go throughpropose_database_change;One server serves every workspace, and an admin can change a workspace's policy at any time. So the text names no workspace and assumes no mode.
The read-only data source sentence is there because
query_databasealways sends the data sourceselectDataSourcepicks, and it prefers a read-only one.SQLService/Querykeeps an explicit data source, so the write never reaches the admin data source. On PostgreSQL the session is read-only, and anINSERTfails with "cannot execute INSERT in a read-only transaction". Routing writes to the admin data source would change what the tool can do, so it isn't part of this PR.The single-database note
propose_database_change's description sent multi-database changes toget_skill("database-change"). It now states the single-database limit, and points a change to several databases in one plan to the console or GitOps. The description and the server instructions take that sentence from one constant, so they can't drift apart. This changes guidance, not capability: an agent can still build a multi-database plan throughcall_api, under the same server checks.Breaking Changes
get_skillMCP tool is removed. A client that calls it gets an unknown-tool error.Release note: "The MCP
get_skilltool is removed. At session start, the MCP server now sends instructions that route agents toquery_database,get_schema,propose_database_change,search_apiandcall_api."Docs
bytebase.comhas no reference toget_skill, thequeryskill or thedatabase-changeskill, onmainor on any branch (git grep, 2026-10-02).docs/integrations/mcp.mdxdescribes the tools without skills, so this PR needs no docs change.For a later docs PR:
docs/integrations/mcp.mdx:118says the query tool runsINSERT,UPDATE,DELETE,CREATE,ALTERandDROP"within your permissions". It has the same read-only data source gap.Not in this change
get_skilltool and its own skill copies (frontend/src/modules/agent/logic/skills/). They are a separate tool, unchanged here.propose_database_change.Tests
TestInitializeServesInstructionsopens a session on the real/mcproute.initializereturns the instructions, they name the five routed tools, andtools/listhas noget_skill. With the instructions option removed, it fails.TestToolGuidanceNamesOnlyRegisteredToolschecks the server instructions and every tool description. Each snake_case name outside a quoted example must be a registered tool. With the oldpropose_database_changenote put back, it fails:propose_database_change description names "get_skill", which is not a registered tool.TestSkillsOnlyInstructServableCallschecked a different rule: every operation a skill named is one the MCP gate serves. That rule goes with the skills, its only subject.TestGetSkillListSkills,TestGetSkillSpecificSkill,TestGetSkillNotFound,TestGetSkillAllSkillsLoadableandTestSkillsOnlyInstructServableCalls.Receipts
query_databasebackend/api/mcp/skills/query.md:30on main; noquery_databasein the filedataSourceIdis optionalbackend/api/v1/sql_service.go:365resolves it before:370checks itbackend/api/mcp/skills/database-change.md:119on mainSheethas noenginefieldproto/v1/v1/sheet_service.proto:92-116backend/api/mcp/server.go:79-82on main (mcp.NewServer(..., nil))ServerOptions.Instructionsoninitializemcp/server.go:1987backend/api/mcp/tool_change.go:150on mainquery_databasesends the read-only data source when there is onetool_resolve.go:449-461prefers READ_ONLY;tool_query.go:177sends itSQLService/Querykeeps an explicit data source and opens it read-onlybackend/api/v1/sql_service.go:2314-2316,:376-382INSERTfailed with SQLSTATE 25006; afterRemoveDataSourcethe sameINSERTlanded🤖 Generated with Claude Code