문서 목차
이 페이지에서목차

flutter-inspector-network

Network debugging specialist. Use for HTTP request/response logging and API analysis

항목내용
모델haiku
사용 도구Read, Glob, Grep
연계 스킬flutter-inspector

A specialized agent for logging and analyzing HTTP requests/responses at runtime.

Triggers#

Automatically activated when @flutter-inspector-network is invoked or the following keywords are detected:

  • API call, HTTP request
  • Network, response
  • Error code, timeout

MCP Tools#

network_get_logs#

Returns recent HTTP request/response logs.

{
  "name": "network_get_logs",
  "description": "HTTP request/response logs",
  "inputSchema": {
    "type": "object",
    "properties": {
      "limit": {
        "type": "integer",
        "description": "Maximum count",
        "default": 50
      },
      "method": {
        "type": "string",
        "description": "Filter: HTTP method (GET, POST, PUT, DELETE)"
      },
      "path": {
        "type": "string",
        "description": "Filter: URL path substring"
      }
    }
  }
}

Response example:

{
  "logs": [
    {
      "id": "req_001",
      "timestamp": "2024-01-01T10:00:00Z",
      "method": "GET",
      "url": "https://api.example.com/users/123",
      "statusCode": 200,
      "duration": 245,
      "requestHeaders": {"Authorization": "Bearer ***"},
      "responseSize": 1024
    },
    {
      "id": "req_002",
      "timestamp": "2024-01-01T10:00:05Z",
      "method": "POST",
      "url": "https://api.example.com/posts",
      "statusCode": 201,
      "duration": 320,
      "requestBody": {"title": "..."},
      "responseSize": 512
    }
  ],
  "totalCount": 2
}

network_get_errors#

Filters and returns only failed requests.

{
  "name": "network_get_errors",
  "description": "Failed request logs",
  "inputSchema": {
    "type": "object",
    "properties": {
      "limit": {
        "type": "integer",
        "description": "Maximum count",
        "default": 20
      }
    }
  }
}

Response example:

{
  "errors": [
    {
      "id": "req_003",
      "timestamp": "2024-01-01T10:01:00Z",
      "method": "GET",
      "url": "https://api.example.com/data",
      "statusCode": 500,
      "duration": 150,
      "errorType": "ServerError",
      "errorMessage": "Internal Server Error",
      "responseBody": {"error": "Database connection failed"}
    },
    {
      "id": "req_004",
      "timestamp": "2024-01-01T10:02:00Z",
      "method": "POST",
      "url": "https://api.example.com/upload",
      "statusCode": null,
      "duration": 30000,
      "errorType": "Timeout",
      "errorMessage": "Connection timed out"
    }
  ],
  "errorCount": 2
}

network_get_stats#

Returns network statistics.

{
  "name": "network_get_stats",
  "description": "Network statistics",
  "inputSchema": {
    "type": "object",
    "properties": {}
  }
}

Response example:

{
  "stats": {
    "totalRequests": 150,
    "successfulRequests": 145,
    "failedRequests": 5,
    "averageDuration": 180,
    "totalBytesReceived": 524288,
    "totalBytesSent": 10240,
    "requestsByMethod": {
      "GET": 100,
      "POST": 40,
      "PUT": 8,
      "DELETE": 2
    },
    "requestsByStatus": {
      "2xx": 140,
      "4xx": 3,
      "5xx": 2,
      "timeout": 5
    }
  },
  "period": "session"
}

network_clear_logs#

Clears network logs.

{
  "name": "network_clear_logs",
  "description": "Clear logs",
  "inputSchema": {
    "type": "object",
    "properties": {}
  }
}

App Integration Code#

// lib/debug/mcp_network_tools.dart
import 'package:mcp_toolkit/mcp_toolkit.dart';
import 'package:dio/dio.dart';

class NetworkLogger extends Interceptor {
  final _logs = <Map<String, dynamic>>[];
  static final instance = NetworkLogger._();
  NetworkLogger._();

  @override
  void onRequest(RequestOptions options, RequestInterceptorHandler handler) {
    _logs.add({
      'id': 'req_${DateTime.now().millisecondsSinceEpoch}',
      'timestamp': DateTime.now().toIso8601String(),
      'method': options.method,
      'url': options.uri.toString(),
      'requestHeaders': _sanitizeHeaders(options.headers),
      'requestBody': options.data,
      'startTime': DateTime.now(),
    });
    handler.next(options);
  }

  @override
  void onResponse(Response response, ResponseInterceptorHandler handler) {
    final log = _logs.lastWhere(
      (l) => l['url'] == response.requestOptions.uri.toString(),
      orElse: () => {},
    );
    if (log.isNotEmpty) {
      log['statusCode'] = response.statusCode;
      log['duration'] = DateTime.now()
          .difference(log['startTime'] as DateTime)
          .inMilliseconds;
      log['responseSize'] = response.data?.toString().length ?? 0;
      log.remove('startTime');
    }
    handler.next(response);
  }

  @override
  void onError(DioException err, ErrorInterceptorHandler handler) {
    final log = _logs.lastWhere(
      (l) => l['url'] == err.requestOptions.uri.toString(),
      orElse: () => {},
    );
    if (log.isNotEmpty) {
      log['statusCode'] = err.response?.statusCode;
      log['duration'] = DateTime.now()
          .difference(log['startTime'] as DateTime)
          .inMilliseconds;
      log['errorType'] = err.type.name;
      log['errorMessage'] = err.message;
      log['responseBody'] = err.response?.data;
      log.remove('startTime');
    }
    handler.next(err);
  }

  Map<String, String> _sanitizeHeaders(Map<String, dynamic> headers) {
    return headers.map((key, value) {
      if (key.toLowerCase() == 'authorization') {
        return MapEntry(key, '***');
      }
      return MapEntry(key, value.toString());
    });
  }

  List<Map<String, dynamic>> getLogs({int? limit, String? method, String? path}) {
    var filtered = _logs.toList();
    if (method != null) {
      filtered = filtered.where((l) => l['method'] == method).toList();
    }
    if (path != null) {
      filtered = filtered.where((l) => (l['url'] as String).contains(path)).toList();
    }
    return filtered.reversed.take(limit ?? 50).toList();
  }

  List<Map<String, dynamic>> getErrors({int? limit}) {
    return _logs
        .where((l) => l['statusCode'] == null || (l['statusCode'] as int) >= 400)
        .toList()
        .reversed
        .take(limit ?? 20)
        .toList();
  }

  Map<String, dynamic> getStats() {
    final successful = _logs.where((l) =>
      l['statusCode'] != null && (l['statusCode'] as int) < 400).length;
    return {
      'totalRequests': _logs.length,
      'successfulRequests': successful,
      'failedRequests': _logs.length - successful,
      // ... additional statistics
    };
  }

  void clear() => _logs.clear();
}

void registerNetworkTools() {
  if (!kDebugMode) return;

  addMcpTool(MCPCallEntry.tool(
    handler: (params) => MCPCallResult(
      message: 'Network logs',
      parameters: {
        'logs': NetworkLogger.instance.getLogs(
          limit: params['limit'] as int?,
          method: params['method'] as String?,
          path: params['path'] as String?,
        ),
      },
    ),
    definition: MCPToolDefinition(
      name: 'network_get_logs',
      description: 'HTTP logs',
      inputSchema: {
        'type': 'object',
        'properties': {
          'limit': {'type': 'integer'},
          'method': {'type': 'string'},
          'path': {'type': 'string'},
        },
      },
    ),
  ));

  // network_get_errors, network_get_stats, network_clear_logs are implemented similarly
}

Usage Examples#

Check recent API calls#

Q: Show me recent API call history
A: Run network_get_logs limit=10
   -> 10 requests (GET /users 200, POST /posts 201, ...)

Filter specific endpoint#

Q: Show me only /users related requests
A: Run network_get_logs path="/users"
   -> Filtered to requests containing /users

Check error requests#

Q: Are there any failed requests?
A: Run network_get_errors
   -> 500 error: /api/data, Timeout: /api/upload

Network statistics#

Q: Summarize the network status
A: Run network_get_stats
   -> 150 requests, 145 successful, 5 failed, avg 180ms

Common Problem Diagnosis#

Slow API response#

1. Check duration with network_get_logs
2. Identify slow requests
3. Determine server performance or network issue

401 Unauthorized#

1. Check 401 errors with network_get_errors
2. Check Authorization in requestHeaders
3. Check token status with auth_get_status

500 Server Error#

1. Check details with network_get_errors
2. Check error message in responseBody
3. Review request parameters

Timeout#

1. Check timeout errors with network_get_errors
2. Check network connection status
3. Review timeout configuration values
  • @flutter-inspector: Master inspector
  • @flutter-inspector-auth: Authentication token issues
  • @flutter-inspector-log: Network related app logs

검색어를 입력하면 문서를 찾습니다.

↑ ↓ 이동 · Enter 열기Esc 닫기