How to Create and Work with MCP Tools for Claude
n
n# How to Create and Work with MCP Tools for Claude
- Updated: Fixed critical string return requirement*
- Overview
MCP (Model Context Protocol) tools allow you to extend Claude's capabilities with custom functionality. This guide shows you how to create, test, and deploy MCP tools in the OpenForum environment.
- Critical Requirements
⚠️ **MOST IMPORTANT**: MCP tools must return **strings only**, never JSON objects or complex data structures.
- ✅ Correct Return Format
```javascript
// Return formatted strings
return "SUCCESS: Task completed successfully";
return "ERROR: Invalid input provided";
return "RESULT: Temperature is 23.5°C";
```- ❌ Incorrect Return Format
```javascript
// Never return objects - this will cause "Input should be a valid string" errors
return {
status: "success",
message: "Task completed"
};
return "item1", "item2";
```- Tool Structure Template
```javascript
if (typeof MyCustomTool == "undefined") {
MyCustomTool = {};
}
MyCustomTool = function() {
var self = this;
self.handleRequest = function(arguments) {
try {
// Extract parameters
var action = arguments.action;
var param1 = arguments.param1;
// Your tool logic here
var result = performAction(action, param1);
// CRITICAL: Always return a string, never an object
return "SUCCESS: " result;
} catch (e) {
return "ERROR: " e.message;
}
};
var performAction = function(action, param) {
// Your implementation here
return "Action completed";
};
return self;
};
```
- Using ProcessBuilder Instead of Process Helper
For tools that need to execute system commands, use `java.lang.ProcessBuilder` instead of the buggy `Process` helper:
```javascript
var runCommand = function(command, workingDir) {
try {
var pb = new java.lang.ProcessBuilder(command.split(" "));
if (workingDir) {
pb.directory(new java.io.File(workingDir));
}
pb.redirectErrorStream(true);
var process = pb.start();
var reader = new java.io.BufferedReader(
new java.io.InputStreamReader(process.getInputStream())
);
var output = "";
var line;
while
line = reader.readLine(
!= null) {
output = line "
n";
}
var exitCode = process.waitFor();
reader.close();
if (exitCode === 0) {
return "SUCCESS: " output.trim();
} else {
return "ERROR: Command failed with exit code " exitCode
"
nOutput: " output.trim();
}
} catch (e) {
return "ERROR: Failed to execute command - " e.message;
}
};
```
- Working with MCPDevTool
The MCPDevTool has been fixed to properly return strings. Here's how to use it:
- 1. Create a New Tool
```javascript
// Use the create action with your tool code
action: "create"
tool_name: "MyAwesomeTool"
tool_code: ""
file_name: "MyAwesomeTool.sjs" // optional
```- 2. Test Tool Syntax
```javascript
action: "test"
tool_name: "MyAwesomeTool"
```- 3. Deploy to Registry
```javascript
action: "deploy"
tool_name: "MyAwesomeTool"
```- 4. Restart Claude
```javascript
action: "restart"
```- 5. List Available Tools
```javascript
action: "list"
```- 6. View Tool Code
```javascript
action: "read"
tool_name: "MyAwesomeTool"
```- Tool Registry
Tools are registered in `/HomeLab/Claude/tool-list.json`:
```json
{
"MyCustomTool": {
"pageName": "/HomeLab/Claude",
"fileName": "MyCustomTool.sjs"
}
}
```
- Common Patterns
- Simple Action Tool
```javascript
self.handleRequest = function(arguments) {
var action = arguments.action || "default";
switch (action) {
case "status":
return "STATUS: System is running";
case "info":
return "INFO: Tool version 1.0";
default:
return "ERROR: Unknown action '" action "'";
}
};
```- File Operations Tool
```javascript
self.handleRequest = function(arguments) {
try {
var fileName = arguments.file_name;
var content = arguments.content;
if (!fileName) {
return "ERROR: file_name parameter required";
}
file.saveAttachment("/HomeLab/Claude", fileName, content);
return "SUCCESS: File saved as " fileName;
} catch (e) {
return "ERROR: " e.message;
}
};
```- Debugging Tips
1. **Check return values**: Ensure all code paths return strings
2. **Use try/catch**: Wrap logic in error handling
3. **Test incrementally**: Use the test action before deploying
4. **Check logs**: Look in Claude Desktop logs for errors
5. **Restart after changes**: Always restart Claude after deploying tools
- Best Practices
- **Descriptive returns**: Include context in return messages
- **Consistent prefixes**: Use "SUCCESS:", "ERROR:", "INFO:" etc.
- **Validate inputs**: Check required parameters exist
- **Handle edge cases**: Plan for null/undefined values
- **Document parameters**: Comment expected arguments
- **Keep it simple**: One tool should do one thing well
- Troubleshooting
- "Input should be a valid string" error:**
- Your tool is returning an object instead of a string
- Check all return statements in your code
- Ensure error handling returns strings too- Tool not found after deployment:**
- Verify tool-list.json was updated correctly
- Restart Claude Desktop
- Check file name matches registry entry
- Use the test action to validate code
- Check for missing semicolons or brackets
- Ensure proper JavaScript syntax- Examples
See the working tools in `/HomeLab/Claude/` for reference:
- `TemperatureTool.sjs` - Simple API call tool
- `JavaTool.sjs` - Complex command execution tool
- `GitTool.sjs` - Multi-action tool with ProcessBuilder
- `MCPDevToolFixed.sjs` - The fixed development tool itself
Remember: **Always return strings, never objects!** This is the most common cause of MCP tool failures.