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
Related Agents#
@flutter-inspector: Master inspector@flutter-inspector-auth: Authentication token issues@flutter-inspector-log: Network related app logs