# ExMCP Troubleshooting Guide

This guide covers common issues and their solutions when working with ExMCP.

## STDIO Transport Issues

### "Unexpected end of JSON input" Error

**Problem**: When using STDIO transport with MCP Inspector or other clients, you see:
```
Error from MCP server: SyntaxError: Unexpected end of JSON input
```

**Cause**: The MCP STDIO protocol requires that ONLY valid JSON-RPC messages appear on stdout. Any other output (logs, Mix.install messages, etc.) contaminates the stream.

**Status**: ✅ **FIXED** - ExMCP now handles non-JSON lines gracefully during startup.

**Common Sources of Contamination**:
1. `Mix.install` output (e.g., "==> ex_mcp", "Compiling...")
2. Logger messages going to stdout instead of stderr
3. Horde registry/supervisor startup logs
4. Any `IO.puts` calls without specifying `:stderr`

**What We Fixed**:
- STDIO server now ignores non-JSON lines instead of sending error responses
- Implemented protocol version negotiation between client and server
- Added configurable startup delay for Mix.install output
- Improved logging configuration for STDIO transport

**Solutions**:

#### For Scripts Using Mix.install

Configure logging BEFORE calling Mix.install:

```elixir
#!/usr/bin/env elixir

# CRITICAL: Configure before Mix.install
Application.put_env(:ex_mcp, :stdio_mode, true)
Application.put_env(:ex_mcp, :stdio_startup_delay, 500)  # ms

# Suppress all logging
System.put_env("ELIXIR_LOG_LEVEL", "emergency")
Application.put_env(:logger, :level, :emergency)

Mix.install([
  {:ex_mcp, "~> 1.0.0-rc.0"}
], verbose: false)

# Your server code here...
```

#### For Production Servers

1. **Use Releases**: Build a release that doesn't need Mix.install (recommended)
2. **Use StdioLauncher**: Helper module that handles startup properly
   ```elixir
   ExMCP.StdioLauncher.start(MyServer, [
     {:ex_mcp, "~> 1.0.0-rc.0"}
   ])
   ```

**Note**: While ExMCP now gracefully handles non-JSON output during startup, Mix.install may still produce some stdout output that cannot be completely suppressed. For absolute zero contamination in production, use compiled releases.

#### Debugging Output

Always send debug output to stderr:
```elixir
# Good
IO.puts(:stderr, "Debug message")

# Bad - contaminates stdout
IO.puts("Debug message")
```

### Server Hangs After Starting

**Problem**: The STDIO server starts but doesn't respond to requests.

**Cause**: The server isn't properly entering STDIO transport mode.

**Solution**: Ensure you're using `transport: :stdio` when starting:
```elixir
MyServer.start_link(transport: :stdio)
```

## DSL Issues

### Tools Not Appearing

**Problem**: Defined tools don't show up when client lists them.

**Cause**: Missing or incorrect callback implementation.

**Solution**: Ensure you implement the `handle_call_tool/3` callback:
```elixir
@impl true
def handle_call_tool(tool_name, args, state) do
  # Handle the tool call
  {:ok, result, state}
end
```

### "Unknown Key" Warnings

**Problem**: Client shows warnings about `__unknown_key__` in responses.

**Cause**: This was a bug in older versions where protocol data was being atomized incorrectly.

**Solution**: Update to the latest version of ExMCP. Protocol data is now kept as strings.

## HTTP Transport Issues

### Port Already in Use

**Problem**: Starting HTTP server fails with "address already in use".

**Solution**: 
1. Check if another server is running on the port
2. Use a different port: `MyServer.start_link(transport: :http, port: 8080)`
3. Kill the existing process using the port

### CORS Errors

**Problem**: Browser clients get CORS errors when connecting.

**Solution**: CORS is enabled by default. If still having issues:
```elixir
MyServer.start_link(
  transport: :http,
  cors_enabled: true
)
```

## General Debugging Tips

### Enable Debug Logging

For non-STDIO transports, enable debug logging:
```elixir
Logger.configure(level: :debug)
```

### Check Server State

Use the BEAM transport for debugging:
```elixir
{:ok, server} = MyServer.start_link(transport: :beam)
:sys.get_state(server)
```

### Test with Simple Client

Use the ExMCP client to test your server:
```elixir
{:ok, client} = ExMCP.Client.connect(url: "stdio://path/to/server.exs")
{:ok, response} = ExMCP.Client.call_tool(client, "tool_name", %{arg: "value"})
```

## Common Mistakes

1. **Using atoms for protocol keys**: Protocol data should use string keys
2. **Not implementing callbacks**: Ensure all required callbacks are implemented
3. **Logging to stdout in STDIO mode**: Always use `:stderr` for STDIO servers
4. **Not handling errors**: Always return proper error tuples from handlers

## Getting Help

If you're still having issues:

1. Check the examples in `examples/getting_started/`
2. Review the test files for usage patterns
3. Open an issue on GitHub with:
   - ExMCP version
   - Elixir/OTP versions
   - Minimal reproduction code
   - Full error messages
