Visitar URL original
fix(mcp)!: replace the stale skills with server instructions by vsai12 · Pull Request #21552 · bytebase/bytebase · GitHub
Skip to content

fix(mcp)!: replace the stale skills with server instructions - #21552

Open
vsai12 wants to merge 2 commits into
mainfrom
fix/mcp-retire-skills
Open

vsai12 wants to merge 2 commits into
mainfrom
fix/mcp-retire-skills

Conversation

@vsai12

@vsai12 vsai12 commented Oct 3, 2026

Copy link
Copy Markdown
Contributor

Ships in the same release as #21551, which makes query_database, get_schema and propose_database_change work for users whose access comes only from project roles. The query skill removed here was their only path until then.

This removes the MCP server's two embedded skills, query and database-change, and the get_skill tool that served them. It adds static server instructions that route an agent to the right tool.

The skills taught the wrong path:

  • query.md:30 lists databases across the whole workspace, and the skill never mentions query_database. It also says dataSourceId is required (query.md:54). SQLService/Query picks a data source when the request has none.
  • database-change.md:119 tells the agent to create the rollout itself, right after it creates the issue.
  • database-change.md:143 tells the agent to add an engine field to the sheet. Sheet has only name, content and content_size.

get_skill served only these two skills, so it goes too. The package's AGENTS.md documented only how to write skills, so it goes with its CLAUDE.md import.

Server instructions

The server sent no instructions before. Now initialize returns a short, static text. It says:

  • which tool to use: query_database for reads, get_schema for schemas, propose_database_change for changes, and search_api then call_api for anything else;
  • that propose_database_change changes one database per call;
  • that under a Read-write policy, query_database can also run DML and DDL, which take effect at once, without an issue or approval;
  • that on an instance with a read-only data source, query_database runs every statement through that data source, so changes there go through propose_database_change;
  • that a refused call states its reason, and a person acts on it in the Bytebase console.

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_database always sends the data source selectDataSource picks, and it prefers a read-only one. SQLService/Query keeps an explicit data source, so the write never reaches the admin data source. On PostgreSQL the session is read-only, and an INSERT fails 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 to get_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 through call_api, under the same server checks.

Breaking Changes

  • The get_skill MCP tool is removed. A client that calls it gets an unknown-tool error.

Release note: "The MCP get_skill tool is removed. At session start, the MCP server now sends instructions that route agents to query_database, get_schema, propose_database_change, search_api and call_api."

Docs

bytebase.com has no reference to get_skill, the query skill or the database-change skill, on main or on any branch (git grep, 2026-10-02). docs/integrations/mcp.mdx describes the tools without skills, so this PR needs no docs change.

For a later docs PR: docs/integrations/mcp.mdx:118 says the query tool runs INSERT, UPDATE, DELETE, CREATE, ALTER and DROP "within your permissions". It has the same read-only data source gap.

Not in this change

  • The page agent has its own get_skill tool and its own skill copies (frontend/src/modules/agent/logic/skills/). They are a separate tool, unchanged here.
  • Multi-database support in propose_database_change.

Tests

  • TestInitializeServesInstructions opens a session on the real /mcp route. initialize returns the instructions, they name the five routed tools, and tools/list has no get_skill. With the instructions option removed, it fails.
  • TestToolGuidanceNamesOnlyRegisteredTools checks the server instructions and every tool description. Each snake_case name outside a quoted example must be a registered tool. With the old propose_database_change note put back, it fails: propose_database_change description names "get_skill", which is not a registered tool.
  • TestSkillsOnlyInstructServableCalls checked a different rule: every operation a skill named is one the MCP gate serves. That rule goes with the skills, its only subject.
  • Deleted with the tool: TestGetSkillListSkills, TestGetSkillSpecificSkill, TestGetSkillNotFound, TestGetSkillAllSkillsLoadable and TestSkillsOnlyInstructServableCalls.

Receipts

Claim Receipt
The query skill lists at the workspace and never names query_database backend/api/mcp/skills/query.md:30 on main; no query_database in the file
dataSourceId is optional backend/api/v1/sql_service.go:365 resolves it before :370 checks it
The change skill creates the rollout backend/api/mcp/skills/database-change.md:119 on main
Sheet has no engine field proto/v1/v1/sheet_service.proto:92-116
The server sent no instructions backend/api/mcp/server.go:79-82 on main (mcp.NewServer(..., nil))
The SDK returns ServerOptions.Instructions on initialize go-sdk v1.7.0 mcp/server.go:1987
The dangling reference backend/api/mcp/tool_change.go:150 on main
query_database sends the read-only data source when there is one tool_resolve.go:449-461 prefers READ_ONLY; tool_query.go:177 sends it
SQLService/Query keeps an explicit data source and opens it read-only backend/api/v1/sql_service.go:2314-2316, :376-382
A write fails there and lands without it live run in the pre-review: with a READ_ONLY data source an INSERT failed with SQLSTATE 25006; after RemoveDataSource the same INSERT landed

🤖 Generated with Claude Code

vsai12 and others added 2 commits October 2, 2026 17:48
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>
Comment thread backend/api/mcp/server.go
- 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.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

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

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants