mcp-devtools
Copilot instructions161 starsChanged 5 months agoApache-2.0View on GitHub
MCP DevTools is a single, high-performance MCP (Model Context Protocol) server written in Go that replaces many Node.js and Python-based MCP servers with one efficient binary. It provides access to essential developer tools through a unified, modular interface that can be easily extended with new tools. Key Features: - Single binary solution replacing multiple resource-heavy servers - 16+ essential developer tools in one package - Built in Go for speed, efficiency, and minimal memory footprint - Fast startup and response…
- Reads credentials
We split this copilot-instructions.md into the rules it gives an agent
72 rules. About 4 are common, 46 are distinctive, and 22 are very specific to this project.
≈4
Common · estimate
Many files like this have a rule of this kind.
≈46
Distinctive · estimate
This author's own choices. Worth a look.
22
Very specific
Tied to their project's names, files or tools. Probably skip.
- Common
- Distinctive
- Very specific
- Distinctive: line 107
Follow Go best practices and idiomatic patterns
- Distinctive: line 108
Use British English spelling throughout code and documentation
- Distinctive: line 109
No marketing terms like "comprehensive" or "production-grade"
- Distinctive: line 111
Keep responses token-efficient (avoid returning unnecessary data)
- Very specific: line 115
Create package under internal/tools/[category]/[toolname]/
- Very specific: line 118
Import the package in internal/imports/tools.go (NOT in main.go)
- Very specific: line 119
Add unit tests in tests/tools/ directory
- Very specific: line 120
Add documentation in docs/tools/ with clear, concise information
- Very specific: line 123
Verify token cost with ENABLE_ADDITIONAL_TOOLS=your_tool_name make benchmark-tokens
- Very specific: line 125
Important: Do NOT add tool imports directly to main.go.
- Distinctive: line 135
When the server runs in stdio mode (default transport), ANY output to stdout/stderr will break the MCP protocol and cause catastrophic …
- Very specific: line 144
Check all exec.Command() calls
- Distinctive: line 145
Ensure stdout/stderr are captured or redirected when server is in stdio mode
- Distinctive: line 146
Consider transport mode when executing external commands
- Distinctive: line 151
Test new dependencies in stdio mode
- Distinctive: line 156
No debug prints left in production code
- Common: line 172
Use proper error handling with wrapped errors
- Distinctive: line 174
Ensure goroutine safety and proper synchronisation
- Distinctive: line 175
Use appropriate logging with logrus logger
- Distinctive: line 176
Follow the project's naming conventions
- Very specific: line 179
All tools MUST implement the tools.Tool interface
- Very specific: line 184
Import new tools in main.go to trigger registration
- Distinctive: line 188
ALL tools accessing files or fetching content from URLs MUST integrate with the security framework
- Very specific: line 189
Use security.NewOperations("tool_name") for HTTP/file operations
- Distinctive: line 191
Check for file access permissions and domain restrictions
- Very specific: line 195
NEVER log to stdout / stderr in stdio mode (breaks MCP protocol, use logrus instead)
- Very specific: line 196
Use proper MCP response formats with mcp.CallToolResult
- Common: line 199
Follow MCP error handling patterns
- Common: line 204
Test error conditions and edge cases
- Distinctive: line 211
Use context timeouts for external requests
- Distinctive: line 212
Avoid blocking operations in tool execution
- Distinctive: line 214
Consider backward compatibility for configuration changes
- Very specific: line 218
Update docs/tools/overview.md when adding tools
- Distinctive: line 221
Document security requirements and limitations
- Distinctive: line 234
Verify proper module imports and dependencies
- Distinctive: line 235
Check for hardcoded credentials or sensitive data
- Distinctive: line 236
Ensure proper resource cleanup (defer statements)
- Distinctive: line 238
Use appropriate data types and structures
- Distinctive: line 239
Follow consistent error message formatting
- Distinctive: line 256
CRITICAL: Before registering a new tool, verify the following:
- Very specific: line 260
Only add tool to defaultTools list in enabledByDefault() (registry.go) if the user has explicitly stated it should be enabled by default
- Distinctive: line 263
When in Doubt - Leave the tool disabled by default.
- Very specific: line 270
Use any instead of interface{}
- Very specific: line 271
Use comparable for type constraints when appropriate
- Very specific: line 275
Use strings.SplitSeq() and strings.FieldsSeq() in range loops instead of strings.Split() and strings.Fields()
- Very specific: line 278
Use for range n instead of for i := 0.
- Very specific: line 279
Use min(a, b) and max(a, b) instead of if/else conditionals
- Very specific: line 282
Use slices.Contains(slice, element) instead of manual loops for searching
- Very specific: line 284
Use maps.Copy(dst, src) instead of manual for k, v := range src { dst[k] = v } loops
- Very specific: line 287
Use t.Context() instead of context.WithCancel() in tests
- Distinctive: line 295
Don't simply wrap existing API endpoints - build thoughtful, high-impact workflow tools
- Distinctive: line 298
Consider what workflows agents actually need to accomplish
- Distinctive: line 304
Default to human-readable identifiers over technical codes (names over IDs)
- Distinctive: line 305
Consider the agent's context budget as a scarce resource
- Distinctive: line 319
Create realistic evaluation scenarios early
- Distinctive: line 324
DRY Principle: No duplicated code between tools
- Common: line 327
Error Handling: All external calls have error handling
- Distinctive: line 328
Documentation: Every tool has comprehensive docstrings/descriptions
- Distinctive: line 348
All tools follow this pattern:
- Distinctive: line 353
Use shared logger and cache for consistency
- Distinctive: line 365
Don't return the information an agent provides to call the tool back to them
- Distinctive: line 366
Avoid any generic information or null / empty fields - these just waste tokens
- Distinctive: line 370
Do not use marketing terms such as 'comprehensive' or 'production-grade' in documentation or code comments.
- Distinctive: line 372
Always use British English spelling, we are not American.
- Distinctive: line 373
Follow the principle of least privileged security.
- Distinctive: line 374
Use 0600 and 0700 permissions for files and directories respectively, unless otherwise specified avoid using 0644 and 0755.
- Distinctive: line 375
All tools should work on both macOS and Linux unless otherwise specified (we do not need to support Windows).
- Distinctive: line 377
When creating new MCP tools make sure descriptions are clear and concise as they are what is used as hints to the AI coding agent using the …
- Distinctive: line 382
CRITICAL: Ensure that when running in stdio mode that we NEVER log to stdout or stderr, as this will break the MCP protocol.
- Distinctive: line 383
When testing the docprocessing tool, unless otherwise instructed always call it with "clear_file_cache": true and do not enable …
- Distinctive: line 412
Before approving any pull request, verify:
- Distinctive: line 427
If you are re-reviewing a PR you've reviewed in the past and your previous comments / suggestions have been addressed or are no longer …
≈ “Common” is an estimate: at least 1 in 5 of the 3,669 Copilot instructions files we read have a rule of the same kind, not the same words. “Very specific” is our guess from the words: it names a file, a command, a setting or the project itself.
Files
GitHub Copilot Instructions for MCP DevTools
Project Overview
MCP DevTools is a single, high-performance MCP (Model Context Protocol) server written in Go that replaces many Node.js and Python-based MCP servers with one efficient binary. It provides access to essential developer tools through a unified, modular interface that can be easily extended with new tools.
Key Features:
- Single binary solution replacing multiple resource-heavy servers
- 16+ essential developer tools in one package
- Built in Go for speed, efficiency, and minimal memory footprint
- Fast startup and response times
- Modular tool registry architecture allowing easy addition of new tools
- Supports multiple transports: stdio (default) and streamable HTTP
Development Setup
Building the Project
# Build the server
make build
# The binary will be created at: bin/mcp-devtoolsRunning the Server
# Run with stdio transport (default)
make run
# Run with HTTP transport
make run-httpTesting
# Run all tests (includes external API integration tests, ~10s)
make test
# Run fast tests (skips external dependencies, ~7s)
make test-fast
# Run tests with detailed timing
make test-verboseLinting and Code Quality
# Format code
make fmt
# Run linters and modernisation checks
make lint
# This runs: gofmt, golangci-lint, and gopls modernizeDependencies
# Install Go dependencies
make deps
# Install all dependencies (Go + Python for document processing)
make install-allProject Structure
mcp-devtools/
├── internal/
│ ├── tools/ # All tool implementations
│ ├── registry/ # Tool registration system
│ ├── security/ # Security framework for file/network operations
│ ├── handlers/ # MCP protocol handlers
│ ├── config/ # Configuration management
│ ├── oauth/ # OAuth functionality
│ ├── cache/ # Caching utilities
│ ├── utils/ # Utility functions
│ └── imports/ # Import management
├── tests/
│ ├── tools/ # Unit tests for tools (REQUIRED for all tools)
│ ├── benchmarks/ # Performance and token cost tests
│ ├── oauth/ # OAuth tests
│ └── unit/ # Unit tests for internal packages
├── docs/
│ └── tools/ # Tool documentation (REQUIRED when adding tools)
├── main.go # Entry point - import new tools here
├── Makefile # Build, test, and development commands
└── mcp.json # MCP server configurationContribution Guidelines
Before Committing
- Format your code:
make fmt - Run linters:
make lint(must pass without errors) - Run tests:
make test-fast(must pass all tests) - Build successfully:
make build(must compile without errors)
Code Standards
- Follow Go best practices and idiomatic patterns
- Use British English spelling throughout code and documentation
- No marketing terms like "comprehensive" or "production-grade"
- Focus on clear, concise, actionable technical guidance
- Keep responses token-efficient (avoid returning unnecessary data)
Adding New Tools
- Create package under
internal/tools/[category]/[toolname]/ - Implement
tools.Toolinterface withDefinition()andExecute()methods - Register tool in
init()function usingregistry.Register(&YourTool{}) - Import the package in
internal/imports/tools.go(NOT inmain.go) - Add unit tests in
tests/tools/directory - Add documentation in
docs/tools/with clear, concise information - Update
docs/tools/overview.md - Integrate with security framework if accessing files/URLs
- Verify token cost with
ENABLE_ADDITIONAL_TOOLS=your_tool_name make benchmark-tokens
Important: Do NOT add tool imports directly to main.go. Use the imports registry system in internal/imports/tools.go instead.
Architecture & Structure
This is a modular MCP (Model Context Protocol) server written in Go with a tool registry architecture. Each tool implements the tools.Tool interface and registers itself through internal/registry/. The main server supports multiple transports (stdio, streamable HTTP).
⚠️ CRITICAL: stdio Mode Logging Violations
MOST IMPORTANT CHECK IN EVERY REVIEW:
When the server runs in stdio mode (default transport), ANY output to stdout/stderr will break the MCP protocol and cause catastrophic failures. This is the #1 bug to prevent.
What to Check in EVERY Pull Request:
- No direct stdout/stderr writes:
- ❌ NEVER:
fmt.Println(),fmt.Printf(),log.Println(),fmt.Fprintf(os.Stdout, ...) - ❌ NEVER:
os.Stdout.Write(),os.Stderr.Write(),print(),println() - ✅ ALWAYS: Use
logger.Info(),logger.Debug(),logger.Error(), etc.
- ❌ NEVER:
- No external commands that write to stdout/stderr in stdio mode:
- Check all
exec.Command()calls - Ensure stdout/stderr are captured or redirected when server is in stdio mode
- Consider transport mode when executing external commands
- Check all
- Check third-party libraries:
- Some libraries may write to stdout/stderr unexpectedly
- Review library documentation before adding dependencies
- Test new dependencies in stdio mode
- Verify error handling:
- Errors should go to logger, not stderr
- Stack traces must use logger, not panic/fatal which write to stderr
- No debug prints left in production code
The only exception is in tests, tests are allowed to write to stdout/stderr.
Why This Matters:
- stdio transport uses stdin/stdout for MCP protocol messages (JSON-RPC)
- Any extra output corrupts the protocol stream
- Results in "unexpected end of JSON input" and protocol failures
- Very difficult to debug once deployed
ACTION REQUIRED: Flag ANY code that might write to stdout/stderr in your review comments with HIGH SEVERITY.
Critical Review Areas
Go Code Standards
- Follow Go best practices and idiomatic patterns
- Use proper error handling with wrapped errors
- Implement context cancellation correctly
- Ensure goroutine safety and proper synchronisation
- Use appropriate logging with logrus logger
- Follow the project's naming conventions
Tool Development Requirements
- All tools MUST implement the
tools.Toolinterface - Tools MUST register via
registry.Register()in theirinit()function - Tools MUST NOT log to stdout / stderr directly (use
logrusinstead) - Execute methods MUST handle context cancellation
- Tools should use shared cache (
sync.Map) for performance - Import new tools in
main.goto trigger registration - Tool responses should be limited to only include information that is actually useful, there's no point in returning the information an agent provides to call the tool back to them, or any generic information or null / empty fields - these just waste tokens.
Security Integration (CRITICAL)
- ALL tools accessing files or fetching content from URLs MUST integrate with the security framework
- Use
security.NewOperations("tool_name")for HTTP/file operations
- Use
- Handle
SecurityErrortypes properly in error responses - Check for file access permissions and domain restrictions
- Any new files should be
0600and directories0700by default to prevent unauthorised access
MCP Protocol Compliance
- NEVER log to stdout / stderr in stdio mode (breaks MCP protocol, use
logrusinstead) - Use proper MCP response formats with
mcp.CallToolResult - Handle tool arguments validation correctly
- Implement proper JSON schema for tool parameters
- Follow MCP error handling patterns
Testing Requirements
- Unit tests MUST be in
tests/tools/directory - Tests MUST NOT rely on external dependencies
- Test error conditions and edge cases
- Tests should be lightweight and fast
Performance & Reliability
- Minimise external API calls and dependencies
- Implement proper caching strategies
- Handle rate limiting gracefully
- Use context timeouts for external requests
- Avoid blocking operations in tool execution
- Maintain compatibility with existing tool interfaces
- Consider backward compatibility for configuration changes
Documentation Standards
- Tool documentation belongs in
docs/tools/ - Update
docs/tools/overview.mdwhen adding tools - Australian English spelling used throughout, No American English spelling used (unless it's a function or parameter to an upstream library)
- Provide clear examples and usage patterns
- Document security requirements and limitations
- Documentation should be concise, favouring clear technical information over verbosity
Code Quality Checks
stdio Mode Logging (Check FIRST, EVERY TIME)
- ❌ Scan entire diff for
fmt.Print,fmt.Println,fmt.Printf,log.Print,print,println - ❌ Check for
os.Stdout.Write,os.Stderr.Write,fmt.Fprintf(os.Stdout,fmt.Fprintf(os.Stderr - ❌ Review all
exec.Command()calls - ensure stdout/stderr are captured - ✅ Confirm all logging uses
logger.Info/Debug/Error/Warn()methods - ✅ Verify error paths don't use
panic()orlog.Fatal()(writes to stderr)
General Code Quality
- Verify proper module imports and dependencies
- Check for hardcoded credentials or sensitive data
- Ensure proper resource cleanup (defer statements)
- Validate input parameters thoroughly
- Use appropriate data types and structures
- Follow consistent error message formatting
Configuration & Environment
- Environment variables should have sensible defaults
- Configuration should be documented in README
- Support both development and production modes
- Handle missing optional dependencies gracefully
Special Attention Areas
- Security framework integration for new tools
- Transport mode compatibility (stdio/streamable HTTP)
- Tool registry and discovery mechanisms
- Memory management and potential leaks
Tool Registration Checklist
CRITICAL: Before registering a new tool, verify the following:
Default Enablement Decision
- By default, ALL new tools are DISABLED - this is the secure default
- Only add tool to
defaultToolslist inenabledByDefault()(registry.go) if the user has explicitly stated it should be enabled by default - If tool is NOT added to defaultTools: It will require
ENABLE_ADDITIONAL_TOOLSto use (this is correct for most tools) - Tests enable the tool via
ENABLE_ADDITIONAL_TOOLSif not in defaultTools list - When in Doubt - Leave the tool disabled by default. It's safer to require explicit enablement than to accidentally expose destructive functionality.
Go Modernisation Rules
CRITICAL: Follow these rules when writing Go code to avoid outdated patterns that modernize would flag:
Types and Interfaces
- Use
anyinstead ofinterface{} - Use
comparablefor type constraints when appropriate
String Operations
- Use
strings.CutPrefix(s, prefix)instead ofif strings.HasPrefix(s, prefix) { s = strings.TrimPrefix(s, prefix) } - Use
strings.SplitSeq()andstrings.FieldsSeq()in range loops instead ofstrings.Split()andstrings.Fields()
Loops and Control Flow
- Use
for range ninstead offor i := 0; i < n; i++when index isn't used - Use
min(a, b)andmax(a, b)instead of if/else conditionals
Slices and Maps
- Use
slices.Contains(slice, element)instead of manual loops for searching - Use
slices.Sort(s)instead ofsort.Slice(s, func(i, j int) bool { return s[i] < s[j] }) - Use
maps.Copy(dst, src)instead of manualfor k, v := range src { dst[k] = v }loops
Testing
- Use
t.Context()instead ofcontext.WithCancel()in tests
Formatting
- Use
fmt.Appendf(nil, format, args...)instead of[]byte(fmt.Sprintf(format, args...))
MCP Development Best Practices
Build for Workflows, Not Just API Endpoints:
- Don't simply wrap existing API endpoints - build thoughtful, high-impact workflow tools
- Consolidate related operations (e.g.,
schedule_eventthat both checks availability and creates event) - Focus on tools that enable complete tasks, not just individual API calls
- Consider what workflows agents actually need to accomplish
Optimise for Limited Context:
- Agents have constrained context windows - make every token count
- Return high-signal information, not exhaustive data dumps
- Provide "concise" vs "detailed" response format options where applicable
- Default to human-readable identifiers over technical codes (names over IDs)
- Consider the agent's context budget as a scarce resource
Design Actionable Error Messages:
- Error messages should guide agents toward correct usage patterns
- Suggest specific next steps: "Try using filter='active_only' to reduce results"
- Make errors educational, not just diagnostic
- Help agents learn proper tool usage through clear feedback
Follow Natural Task Subdivisions:
- Tool names should reflect how humans think about tasks
- Group related tools with consistent prefixes for discoverability
- Design tools around natural workflows, not just API structure
Use Evaluation-Driven Development:
- Create realistic evaluation scenarios early
- Let agent feedback drive tool improvements
- Prototype quickly and iterate based on actual agent performance
To ensure quality, review the code for:
- DRY Principle: No duplicated code between tools
- Composability: Shared logic extracted into functions
- Consistency: Similar operations return similar formats
- Error Handling: All external calls have error handling
- Documentation: Every tool has comprehensive docstrings/descriptions
OpenTelemetry Tracing Patterns
Session span parent-child relationships: Session spans in internal/telemetry/tracer.go must be ended immediately followed by ForceFlush() to ensure they export to the backend before child tool spans. Without force flush, the OTEL batch processor exports asynchronously, causing child spans to arrive before their parent, resulting in "invalid parent span IDs" warnings in Jaeger.
sessionSpan.End()
// CRITICAL: Force flush ensures parent exports before children
if tp != nil {
ctx, cancel := context.WithTimeout(context.Background(), 2*time.Second)
defer cancel()
_ = tp.ForceFlush(ctx)
}Tool spans inherit trace context via W3C Trace Context propagation (inject→extract pattern) in StartToolSpan().
Tool Development Pattern
All tools follow this pattern:
- Define struct implementing
tools.Tool - Register in
init()withregistry.Register() - Implement
Definition()for MCP tool schema - Implement
Execute()for tool logic - Use shared logger and cache for consistency
Tool Descriptions Best Practices
- Tool descriptions should focus on WHAT the tool does
- Tool descriptions should be action-oriented and concise
- ✅ Good: "Returns source code structure by stripping function/method bodies whilst preserving signatures, types, and declarations."
- ❌ Poor: "Transform source code by removing implementation details while preserving structure. Achieves 60-80% token reduction for optimising AI context windows"
- The first describes what the tool does; the second explains why it's useful (which bloats the context unnecessarily)
- Tool descriptions should aim to be under 200 characters where possible; save detailed usage information for Extended Help
Tool Response Best Practices
- Tool responses should be limited to only include information that is actually useful
- Don't return the information an agent provides to call the tool back to them
- Avoid any generic information or null / empty fields - these just waste tokens
General Guidelines
- Do not use marketing terms such as 'comprehensive' or 'production-grade' in documentation or code comments.
- Focus on clear, concise actionable technical guidance.
- Always use British English spelling, we are not American.
- Follow the principle of least privileged security.
- Use 0600 and 0700 permissions for files and directories respectively, unless otherwise specified avoid using 0644 and 0755.
- All tools should work on both macOS and Linux unless otherwise specified (we do not need to support Windows).
- Rather than creating lots of tools for one purpose / provider, instead favour creating a single tool with multiple functions and parameters.
- When creating new MCP tools make sure descriptions are clear and concise as they are what is used as hints to the AI coding agent using the tool, you should also make good use of MCP's annotations.
- Tools use the
internal/mcpapipackage, which wraps the official https://github.com/modelcontextprotocol/go-sdk. See docs/creating-new-tools.md.
Important Warnings and Reminders
- CRITICAL: Ensure that when running in stdio mode that we NEVER log to stdout or stderr, as this will break the MCP protocol.
- When testing the docprocessing tool, unless otherwise instructed always call it with "clear_file_cache": true and do not enable return_inline_only
- If you're wanting to call a tool you've just made changes to directly (rather than using the command line approach), you have to let the user know to restart the conversation otherwise you'll only have access to the old version of the tool functions directly.
- When adding new tools ensure they are registered in the list of available tools in the server (within their init function), ensure they have a basic unit test, and that they have docs/tools/
<toolname>.md with concise, clear information about the tool and that they're mentioned in the main README.md and docs/tools/overview.md. - We should be mindful of the risks of code injection and other security risks when parsing any information from external sources.
- On occasion the user may ask you to build a new tool and provide reference code or information in a provided directory such as
tmp_repo_clones/<dirname>unless specified otherwise this should only be used for reference and learning purposes, we don't ever want to use code that directory as part of the project's codebase. - After making changes and performing a build if you need to test the MCP server with the updated changes you MUST either test it from the command line - or STOP and ask the user to restart the MCP client otherwise you won't pick up the latest changes
- YOU MUST ALWAYS run
make lint && make test && make buildetc... to build the project rather than gofmt, go build or test directly, and you MUST always do this before stating you've completed your changes!
Quick Debugging Tips
You can debug the tool by running it in debug mode interactively, e.g.:
rm -f debug.log; pkill -f "mcp-devtools.*" ; echo '{"jsonrpc": "2.0", "id": 1, "method": "tools/call", "params": {"name": "fetch_url", "arguments": {"url": "https://go.dev", "max_length": 500, "raw": false}}}' | ./bin/mcp-devtools stdioOr with API key:
BRAVE_API_KEY="ask the user if you need this" ./bin/mcp-devtools stdio <<< '{"jsonrpc": "2.0", "id": 1, "method": "tools/call", "params": {"name": "brave_search", "arguments": {"type": "web", "query": "cat facts", "count": 1}}}'Lint Github Actions
actionlintReview Checklist for Every PR
Before approving any pull request, verify:
- [CRITICAL] No stdout/stderr writes in stdio mode (see section above)
- All new tools implement
tools.Toolinterface correctly - Security framework integration for file/network operations
- Documentation updated in
docs/tools/if required - Error handling uses wrapped errors (
fmt.Errorfwith%w) - Context cancellation handled properly
- Resource cleanup with defer statements
- British English spelling used throughout, No American English spelling used (unless it's a function or parameter to an upstream library)
- New tools are disabled by default unless explicitly approved
- Tool imports added to
internal/imports/tools.go(NOTmain.go) - Go modernisation rules followed (use
any,strings.CutPrefix, etc.) - Tool descriptions are concise and action-oriented (<200 chars where possible)
If you are re-reviewing a PR you've reviewed in the past and your previous comments / suggestions have been addressed or are no longer valid please resolve those previous review comments to keep the review history clean and easy to follow.
Where files are headingNew Copilot instructions files have more rules about branches and pull requests, and fewer about code style.
Of the Copilot instructions files we read, the 2,297 first seen in the last six months, against the older ones: the kind of rule that gained most share, and the kind that lost most. About files like this in general, not this one, and an estimate, since a kind is a pattern in the words.
In this repositoryOne other file it gives its agents.
- CLAUDE.mdCLAUDE.md
Does it work?
Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.
Reviews can't be read right now.
Your trail
Files you open will collect here, so you can find them again.
Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.
Now do this for your own.
Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.

