OpenCode tools: stop blind trust with permission checks
OpenCode serves 7.5 million monthly active developers by mid-2026, yet its default configuration grants unrestricted tool access without permission checks. Json`.
The platform's rapid ascent to over 170,000 GitHub stars highlights its dominance, but this scale amplifies the risk of unauthorized actions when tool permissions remain unconfigured. By default, the system allows any LLM to run shell commands or overwrite files via the write tool without user approval. Understanding these mechanics is critical because the difference between a helpful agent and a compromised repository often lies in a single configuration flag.
Readers will learn to replace blind trust with granular control by configuring permission fields to require approval for sensitive operations. Mastering these settings ensures that the automation powering your development workflow remains a servant to your security policy rather than a threat vector.
The Role of Tools and MCP Servers in OpenCode Architecture
Defining OpenCode Tools: Built-in Bash, Edit, and LSP Functions
OpenCode defines a tool as a specific function call that permits an LLM to execute actions like file editing or shell commands within a codebase. The platform ships with a reliable suite of built-in utilities: bash, edit, write, read, grep, glob, lsp, apply_patch, skill, todowrite, and webfetch. The edit tool acts as the primary mechanism for code modification, applying exact string replacements to existing files rather than rewriting entire blocks. For broader environmental interaction, bash executes shell commands such as dependency installation or version control operations directly in the project context.
Developers extend functionality beyond these defaults by integrating MCP servers or defining custom tools. The lsp utility provides code intelligence features like definition lookup and reference finding by interacting with configured Language Server Protocol servers. Custom tools keyed by name override built-in equivalents, permitting targeted behavioral adjustments without altering the core binary. All tools are enabled by default and do not require permission to run. Users control tool behavior through the `permission` field in `opencode.json`, setting values to "allow", "deny", or "ask" (require approval). This granular control ensures the LLM acts as a constrained agent rather than an unrestricted user. Operators configure approval workflows for specific actions like bash execution while allowing read-only tools like grep to run freely, or use wildcards to control multiple tools simultaneously.
Applying Custom Tools and MCP Servers for Database Access
Extending OpenCode beyond file manipulation requires defining custom tools or connecting MCP servers for external service integration. This architectural approach allows the system to interact with external resources through standardized server connections rather than relying solely on local file operations. Operators configure these extensions in `opencode.json`, where custom definitions keyed by name take precedence over default behaviors. This allows teams to wrap complex SQL queries or API calls into safe, parameterized functions that the LLM invokes via function calling.
| Feature | Built-in Tools | Custom/MCP Tools |
|---|---|---|
| Scope | Filesystem and Shell | External APIs, Databases |
| Execution | Local environment | External service integration |
| Config | Enabled by default | Requires definition |
The platform supports connectivity to more than 75 different LLM providers, allowing for extensive model agnosticism. Broader automation capabilities demand clear permission schemas to manage access to external resources effectively.
Security Risks of Arbitrary Code Execution in Custom OpenCode Tools
Custom tools function as user-set functions capable of executing code within the host environment. By default, all tools are enabled and do not require permission to run, but users restrict access by configuring `opencode.json` to deny or require approval for specific tools like bash or write. The system allows operators to set permissions to "allow", "deny", or "ask" for each tool individually. Custom definitions keyed by name take precedence over built-in utilities, allowing potential override of safe defaults.
The platform emphasizes safety and control through its permission model, where tool behavior is explicitly managed via configuration. Without strict separation of reasoning and execution, an agent could perform unauthorized actions if a custom function lacks proper guardrails. OpenCode has accumulated over 170,000 stars on GitHub by mid-2026, reflecting its widespread adoption and scrutiny. The development community consists of over 900 contributors who have collaborated on the codebase to prevent vendor lock-in. Builders must treat custom function definitions as trusted entry points requiring rigorous validation before deployment.
Internal Mechanics of Search Execution and Patch Application
Ripgrep Pattern Matching and Gitignore Exclusion Logic
Search requests from the grep and glob tools route directly to ripgrep, which automatically respects `.gitignore` patterns to filter out listed files. Operators can override this default exclusion logic by placing a `.ignore` file in the project root, explicitly re-including directories like `node_modules` or `dist` when full-context analysis becomes necessary. While grep matches file content using regular expressions, glob operates strictly on file paths using syntax such as `/*.ts`. The apply_patch tool functions differently by consuming `patchText` containing embedded markers like `* Update File` rather than performing pattern matching. This separation means search tools define the context window, while patching tools apply deterministic changes. Strict adherence to `.gitignore` improves signal-to-noise ratios for code queries but risks blinding the agent to configuration files often excluded by default. Developers must verify their ignore rules do not inadvertently hide critical infrastructure definitions from the LLM's view. The permission system enforces boundaries through explicit allow, deny, or ask settings set in `opencode.json`.
Configuring.ignore Files to Include node_modules and dist
Users can create a `.ignore` file in the project root to include normally ignored files. Built-in tools respect `.gitignore` patterns to filter noise, yet specific debugging sessions often require visibility into `node_modules` or `dist` directories. Placing inversion rules like `!node_modules/` and `!dist/` in this local configuration allows ripgrep to search within those directories even if they are listed in `.gitignore`. This approach resolves the common failure mode where dependency code remains invisible to grep queries. Modifying the shared `.gitignore` risks breaking builds for collaborators, whereas the `.ignore` file acts as a local override layer. This distinction allows operators to maintain clean repository standards while granting temporary, deep-scope access for specific analysis tasks. The mechanism relies on ripgrep using these local files to expand search visibility beyond standard git-set exclusions. Flexibility introduces a risk of context pollution if broad wildcards are applied indiscriminately. Searching entire dependency trees can increase the volume of data processed, potentially impacting performance. Operators should scope these overrides to specific subdirectories rather than inverting entire hierarchies.
Developers enforcing consistent workflow rules across a team might instead apply `AGENTS.md` files to define persistent guardrails that survive session restarts. Temporary search depth does not permanently alter the project's exclusion logic with this separation. Immediate investigative power conflicts with long-term signal-to-noise ratio maintenance. Precise control over search scope prevents the agent from hallucinating requirements based on transitive dependencies.
Edit Tool String Replacement Versus Write Tool Overwrite
The edit tool modifies existing files using exact string replacements, whereas write creates new files or overwrites existing ones entirely. This mechanical distinction determines how the LLM interacts with the codebase during patch application. Edit operates as a surgical instrument, requiring the target text to match the source exactly to succeed, making it the primary method for refactoring logic without altering file metadata. Write functions as a blunt replacement mechanism; if a file already exists, the tool discards the original content completely before saving the new version.
Write carries a higher risk of accidental data loss if the LLM misidentifies a file's necessity, as it does not merge changes. The edit tool requires exact matches to function, failing if the target text differs from the source. Edit struggles with large-scale structural changes where context shifting makes exact matching improbable. The system relies on apply_patch to handle complex diffs using marker lines like `* Update File` relative to the project root in these scenarios. This separation enforces a boundary between reasoning and execution, ensuring AI agents operate within the permissions set in `opencode.json`. Builders should default to edit for iterative improvements and reserve write for initial scaffolding or when a complete file reset is the intended outcome.
Configuring Tool Permissions and Security Boundaries
Defining opencode.json Permission Modes: Allow, Deny, and Ask
The `permission` field inside `opencode.json` draws a hard line between model reasoning and actual system execution. Engineers map specific tool names to explicit access states to enforce safety policies before any code modification occurs. Three distinct modes govern this behavior: `allow` grants immediate execution, `deny` blocks the action entirely, and `ask` requires manual approval for every single invocation. This model prevents unauthorized shell access while keeping workflow fluid for safe operations like reading files. Wildcards extend these rules to flexible toolsets, such as requiring approval for all tools from a specific MCP server using the pattern `"mymcp_*": "ask"`. By default, all tools are enabled and do not require permission to run, yet operators can override this baseline behavior through these permissions. Unlike static allow-lists, this system matches keys as wildcard patterns, allowing granular control over custom functions without rewriting core logic. Teams explicitly set permissions for utilities like bash or write to manage environment interactions during autonomous runs.
Using Wildcards to Secure MCP Servers and Bash Tools
Wildcard patterns like `"mymcp_*": "ask"` instantly gate entire MCP server toolsets behind manual approval. This configuration prevents unauthorized execution across flexible integrations by grouping tools under a single permission rule. Operators configure dangerous utilities like bash to `ask` rather than `allow`, forcing human verification before the LLM runs shell commands such as `npm install` or `git status`. The bash tool executes shell commands in the project environment, while the write tool creates new files or overwrites existing ones.
- Define the `permission` object in `opencode.json` to establish your security baseline.
- Apply wildcard syntax to target specific MCP server prefixes without listing individual tools.
- Set high-risk tools to `ask` to ensure every execution requires explicit user consent.
This approach treats the permission model as a scalable filter rather than a static list. When managing large MCP deployments, wildcard rules allow operators to require approval for all tools from a specific server using a single pattern.
Validating Read, Grep, and Glob Tool Access Rules
Verify read, grep, and glob scoping to manage data access before enabling write capabilities. These tools form the observation layer, and their configuration determines exactly how agents inspect the codebase.
- Configure read permissions, noting the tool supports reading specific line ranges for large files.
- Configure grep to apply full regex syntax and file pattern filtering for fast content searches.
- Use glob patterns like `/*.js` or `src//*.ts` to find files, with results sorted by modification time.
| Tool | Primary Function | Configuration Note |
|---|---|---|
| read | Read file contents | Supports specific line ranges |
| grep | Search file contents | Uses full regex syntax |
| glob | Find files by pattern | Returns paths sorted by time |
The operational balance lies between debugging depth and access scope; broadening search paths aids the agent in resolving dependencies but increases the volume of accessible data. Unlike write operations, read-only tools like read, grep, and glob do not modify code, yet they provide visibility into the project structure. Internally, tools like grep and glob apply ripgrep, which respects `.gitignore` patterns by default, excluding listed files and directories from searches unless overridden by a `.ignore` file.
Extending Functionality with Custom Tools and Web Integrations
Defining Custom Tool Functions in Config Files
Defining custom tool functions in the config file extends the LLM's execution boundary beyond built-in capabilities like `read` or `bash`. These user-set functions, declared within `opencode.json` or the global `~/.config/opencode/tools/` directory, enable the agent to execute arbitrary code tailored to specific project workflows. Unlike static built-ins, custom tools keyed by name take precedence over default behaviors, allowing developers to override standard operations with specialized logic. This precedence rule ensures that project-specific guardrails always supersede generic defaults when naming conflicts occur. Implementation relies on the `tool` helper to maintain type safety while defining these executable signatures. A significant architectural consequence involves the merger of settings from multiple sources, where managed organization settings override project-level `.opencode` directories, which in turn override global configs. This hierarchy means a custom tool set globally might be silently replaced by a project manager, requiring operators to audit the full configuration chain before deployment.
| Source Level | Precedence | Scope |
|---|---|---|
| Managed Settings | Highest | Organization-wide |
| Project Config | Medium | Repository-specific |
| Global Config | Lowest | User environment |
Configuration directories apply specific pluralized subdirectories including `agents/`, `commands/`, `modes/`, `plugins/`, `skills/`, `tools/`, and `themes/` for organized management. For further guidance on structuring these definitions, refer to the documentation on creating custom tools. As noted by industry trends, this modular approach prevents vendor lock-in by decoupling tool logic from the underlying model provider.
Application: Integrating Database Access via MCP Servers
Connect external databases by registering MCP servers to expose live schema context directly to the coding agent. This integration replaces static documentation with flexible tool discovery, allowing the LLM to query table structures before generating SQL. Unlike custom flows that consume excessive tokens, standardized server connections reduce overhead while expanding the agent's operational boundary. By default, all tools are enabled and do not require permission to run, though tool behavior can be controlled through permissions. Operators must explicitly configure `opencode.json` to gate database modifications behind manual approval workflows.
- Define the MCP server connection in the configuration file to establish the transport layer.
- Apply wildcard rules like `"db_mcp_*": "ask"` to force human verification on write operations.
- Restrict webfetch capabilities separately to control the agent's ability to fetch external content.
Since session persistence relies on local SQLite databases, conversation history containing sensitive connection strings never leaves the user environment, yet the execution path remains vulnerable to prompt injection without strict tool gating.
| Configuration Mode | Effect on MCP Tools | Risk Profile |
|---|---|---|
| `allow` | Immediate execution | High |
| `ask` | Requires approval | Medium |
| `deny` | Blocks access | None |
Neglecting this granular control allows an agent to execute arbitrary code via exposed custom tools, potentially compromising the entire host environment.
Economic Advantages of Bring-Your-Own-Key Models
OpenCode avoids the $20/month subscription fee common to IDEs like Cursor by using a bring-your-own-key financial structure. This model decouples tool management from inference costs, ensuring developers pay only for token usage via external providers while the core software remains free under an MIT license. Unlike Claude Code, which restricts users to Anthropic models, this approach allows selection of specific providers to optimize price-performance ratios based on project needs. The ability to select specific providers allows teams to route traffic through cheaper APIs during bulk operations, a flexibility absent in bundled offerings. However, this cost efficiency shifts the burden of key management and usage monitoring entirely to the developer, requiring disciplined tracking to prevent unexpected bills from external providers. Integrating strict permission controls helps mitigate risks associated with unrestricted tool execution in this decentralized model.
About
Marcus Chen, Lead Agent Engineer at AI Agents News, brings deep practical expertise to the analysis of OpenCode's tool management system. Having shipped production multi-agent systems, Chen understands that effective orchestration relies heavily on how agents access and execute external functions. His daily work involves evaluating frameworks like CrewAI and AutoGen, where tool calling mechanics often determine system reliability. This article dissects OpenCode's permission structures and MCP server integrations, reflecting Chen's focus on concrete engineering controls rather than theoretical capabilities. At AI Agents News, the mission is to provide technical founders and engineers with actionable insights on autonomous agents. By connecting OpenCode's configuration options to real-world deployment scenarios, Chen helps readers navigate the complexities of function calling security and extensibility. His analysis ensures builders can make informed decisions about integrating these tools into their own coding agent workflows without falling for vendor hype.
Conclusion
Scaling decentralized agent architectures reveals that cost savings from bring-your-own-key models quickly erode without rigorous operational discipline. While avoiding fixed subscription fees offers immediate financial relief, the operational overhead of managing disparate API keys and monitoring token consumption across multiple providers creates a hidden tax on developer time. Teams often underestimate the friction involved in tracking usage spikes when tool management is fully decoupled from inference, leading to budget unpredictability that fixed-cost alternatives simply absorb.
Adopt OpenCode only if your organization possesses the maturity to implement strict permission gates and automated usage auditing within the first month of deployment. This approach is ill-suited for teams lacking established FinOps practices for AI spending, as the risk of runaway costs outweighs the benefit of avoiding standard IDE fees. The resistance to vendor lock-in drives valuable innovation, but it demands proactive governance rather than passive consumption.
Start by configuring wildcard rules to force human verification on all write operations before connecting any external model provider. This single step establishes the necessary boundary between agent autonomy and system integrity, ensuring that the flexibility of custom tools does not compromise your host environment.
Frequently Asked Questions
All tools run without permission checks by default. This exposes the 7.5 million developer community to potential unauthorized code execution if configurations remain unchanged.
Set permission fields to deny or ask in your config file. This protects the 7.5 million active users by preventing automatic shell commands or file overwrites.
Yes, use wildcard characters to control groups of tools simultaneously.
You gain code intelligence like definitions and references.
Custom definitions keyed by name take precedence over built-in utilities.