SpyBara
Go Premium Account
2026
27 Oct 2025, 18:02
12 May 2026, 16:02 12 May 2026, 14:59 12 May 2026, 01:59 12 May 2026, 00:01 11 May 2026, 23:00 11 May 2026, 21:57 11 May 2026, 20:02 11 May 2026, 18:59 11 May 2026, 18:00 11 May 2026, 15:00 10 May 2026, 23:03 10 May 2026, 17:00 10 May 2026, 04:02 9 May 2026, 04:57 9 May 2026, 04:01 9 May 2026, 03:01 8 May 2026, 22:00 8 May 2026, 19:00 8 May 2026, 18:00 8 May 2026, 16:57 8 May 2026, 07:02 8 May 2026, 06:02 8 May 2026, 03:01 8 May 2026, 02:03 8 May 2026, 01:02 8 May 2026, 00:02 7 May 2026, 22:59 7 May 2026, 21:57 7 May 2026, 17:08 5 May 2026, 23:00 5 May 2026, 21:00 5 May 2026, 17:00 5 May 2026, 15:59 5 May 2026, 14:57 5 May 2026, 00:02 4 May 2026, 22:58 4 May 2026, 22:01 4 May 2026, 18:58 4 May 2026, 15:35 4 May 2026, 06:55 4 May 2026, 04:18 2 May 2026, 18:14 2 May 2026, 04:05 2 May 2026, 00:19 1 May 2026, 18:19 1 May 2026, 04:22 1 May 2026, 00:20 29 Apr 2026, 21:21 29 Apr 2026, 15:36 29 Apr 2026, 09:39 29 Apr 2026, 04:11 29 Apr 2026, 00:20 28 Apr 2026, 21:21 28 Apr 2026, 18:28 28 Apr 2026, 15:45 28 Apr 2026, 06:49 27 Apr 2026, 21:20 27 Apr 2026, 18:23 26 Apr 2026, 04:08 25 Apr 2026, 21:10 24 Apr 2026, 18:11 24 Apr 2026, 06:34 24 Apr 2026, 00:17 23 Apr 2026, 18:19 23 Apr 2026, 04:04 23 Apr 2026, 00:17 22 Apr 2026, 21:15 22 Apr 2026, 04:00 22 Apr 2026, 00:13 21 Apr 2026, 21:14 21 Apr 2026, 09:30 21 Apr 2026, 04:01 20 Apr 2026, 21:14 20 Apr 2026, 18:16 18 Apr 2026, 18:09 18 Apr 2026, 00:13 17 Apr 2026, 21:13 17 Apr 2026, 18:14 17 Apr 2026, 00:15 16 Apr 2026, 21:13 16 Apr 2026, 18:21 16 Apr 2026, 15:30 16 Apr 2026, 04:02 16 Apr 2026, 00:16 15 Apr 2026, 18:20 15 Apr 2026, 15:24 15 Apr 2026, 09:29 15 Apr 2026, 04:00 14 Apr 2026, 21:14 14 Apr 2026, 18:21 14 Apr 2026, 06:32 14 Apr 2026, 04:00 14 Apr 2026, 00:16 13 Apr 2026, 21:14 13 Apr 2026, 18:21 11 Apr 2026, 00:11 10 Apr 2026, 21:09 10 Apr 2026, 18:13 10 Apr 2026, 06:32 10 Apr 2026, 00:12 9 Apr 2026, 21:14 9 Apr 2026, 18:17 9 Apr 2026, 15:29 9 Apr 2026, 03:55 9 Apr 2026, 00:09 8 Apr 2026, 21:13 8 Apr 2026, 18:21 8 Apr 2026, 15:27 8 Apr 2026, 00:12 7 Apr 2026, 21:14 4 Apr 2026, 18:05 4 Apr 2026, 03:46 4 Apr 2026, 00:09 3 Apr 2026, 21:07 3 Apr 2026, 18:08 3 Apr 2026, 03:54 3 Apr 2026, 00:11 2 Apr 2026, 21:08 2 Apr 2026, 18:12 2 Apr 2026, 09:19 2 Apr 2026, 06:21 2 Apr 2026, 03:53 1 Apr 2026, 21:12 1 Apr 2026, 18:13 1 Apr 2026, 04:00 1 Apr 2026, 00:11 31 Mar 2026, 21:09 31 Mar 2026, 06:24 31 Mar 2026, 03:56 31 Mar 2026, 00:11 30 Mar 2026, 21:13 30 Mar 2026, 18:15 28 Mar 2026, 18:04 28 Mar 2026, 15:06 27 Mar 2026, 21:09 27 Mar 2026, 18:14 27 Mar 2026, 15:15 27 Mar 2026, 06:21 27 Mar 2026, 03:56 27 Mar 2026, 00:10 26 Mar 2026, 21:07 26 Mar 2026, 18:16 26 Mar 2026, 15:25 26 Mar 2026, 06:21 26 Mar 2026, 03:55 26 Mar 2026, 00:10 25 Mar 2026, 21:08 25 Mar 2026, 18:15 25 Mar 2026, 06:18 25 Mar 2026, 03:47 25 Mar 2026, 00:08 24 Mar 2026, 18:15 24 Mar 2026, 00:07 23 Mar 2026, 21:08 23 Mar 2026, 18:13 23 Mar 2026, 00:09 22 Mar 2026, 18:04 22 Mar 2026, 00:07 21 Mar 2026, 18:03 21 Mar 2026, 00:07 20 Mar 2026, 21:05 20 Mar 2026, 18:08 20 Mar 2026, 15:13 20 Mar 2026, 03:45 20 Mar 2026, 00:08 19 Mar 2026, 06:17 19 Mar 2026, 00:08 18 Mar 2026, 18:16 18 Mar 2026, 12:11 18 Mar 2026, 09:15 18 Mar 2026, 03:50 18 Mar 2026, 00:09 17 Mar 2026, 21:10 17 Mar 2026, 18:15 17 Mar 2026, 03:46 17 Mar 2026, 00:08 16 Mar 2026, 21:10 16 Mar 2026, 18:15 14 Mar 2026, 03:44 14 Mar 2026, 00:08 13 Mar 2026, 21:07 13 Mar 2026, 18:07 13 Mar 2026, 06:12 12 Mar 2026, 21:07 12 Mar 2026, 18:12 12 Mar 2026, 00:07 11 Mar 2026, 03:43 11 Mar 2026, 00:05 10 Mar 2026, 03:43 10 Mar 2026, 00:05 9 Mar 2026, 21:06 7 Mar 2026, 03:37 7 Mar 2026, 00:07 6 Mar 2026, 06:10 6 Mar 2026, 03:44 6 Mar 2026, 00:12 5 Mar 2026, 06:12 5 Mar 2026, 03:45 5 Mar 2026, 00:07 4 Mar 2026, 21:06 4 Mar 2026, 18:09 4 Mar 2026, 09:09 1 Mar 2026, 06:10 1 Mar 2026, 03:49 28 Feb 2026, 21:01 28 Feb 2026, 00:05 27 Feb 2026, 21:05 27 Feb 2026, 18:07 27 Feb 2026, 09:11 27 Feb 2026, 06:13 27 Feb 2026, 00:08 26 Feb 2026, 21:08 26 Feb 2026, 18:12 26 Feb 2026, 09:14 26 Feb 2026, 06:17 26 Feb 2026, 00:07 25 Feb 2026, 03:47 25 Feb 2026, 00:09 24 Feb 2026, 21:08 24 Feb 2026, 18:15 23 Feb 2026, 21:13 21 Feb 2026, 18:03 21 Feb 2026, 06:08 20 Feb 2026, 21:03 20 Feb 2026, 06:14 20 Feb 2026, 00:07 19 Feb 2026, 21:06 19 Feb 2026, 03:48 19 Feb 2026, 00:08 18 Feb 2026, 03:48 17 Feb 2026, 21:08 17 Feb 2026, 00:08 16 Feb 2026, 21:05 14 Feb 2026, 03:44 13 Feb 2026, 21:09 12 Feb 2026, 00:06 11 Feb 2026, 21:10 11 Feb 2026, 00:11 10 Feb 2026, 21:13 10 Feb 2026, 03:56 10 Feb 2026, 00:11 9 Feb 2026, 15:17 9 Feb 2026, 00:08 7 Feb 2026, 21:05 7 Feb 2026, 18:03 7 Feb 2026, 03:43 6 Feb 2026, 21:06 6 Feb 2026, 00:05 5 Feb 2026, 21:06 5 Feb 2026, 18:13 5 Feb 2026, 03:46 5 Feb 2026, 00:07 4 Feb 2026, 21:07 4 Feb 2026, 18:11 4 Feb 2026, 03:45 4 Feb 2026, 00:06 3 Feb 2026, 21:08 3 Feb 2026, 18:14 3 Feb 2026, 09:10 3 Feb 2026, 03:46 1 Feb 2026, 21:03 1 Feb 2026, 18:02 31 Jan 2026, 03:42 31 Jan 2026, 00:06 30 Jan 2026, 18:07 30 Jan 2026, 00:06 29 Jan 2026, 21:03 28 Jan 2026, 15:06 28 Jan 2026, 03:30 28 Jan 2026, 00:05 27 Jan 2026, 21:01 27 Jan 2026, 18:03 27 Jan 2026, 06:02 26 Jan 2026, 21:03 25 Jan 2026, 03:34 24 Jan 2026, 03:29 23 Jan 2026, 21:01 23 Jan 2026, 18:02 23 Jan 2026, 00:05 22 Jan 2026, 21:03 22 Jan 2026, 15:05 22 Jan 2026, 03:31 22 Jan 2026, 00:05 21 Jan 2026, 21:05 21 Jan 2026, 06:02 21 Jan 2026, 03:30 21 Jan 2026, 00:05 20 Jan 2026, 21:03 20 Jan 2026, 18:03 20 Jan 2026, 15:05 20 Jan 2026, 03:30 19 Jan 2026, 21:01 19 Jan 2026, 00:05 16 Jan 2026, 21:01 16 Jan 2026, 18:02 16 Jan 2026, 15:02 16 Jan 2026, 00:05 14 Jan 2026, 06:02 14 Jan 2026, 00:05 12 Jan 2026, 21:02 12 Jan 2026, 18:02 12 Jan 2026, 00:05 11 Jan 2026, 18:02 11 Jan 2026, 03:31 11 Jan 2026, 00:06 10 Jan 2026, 21:01 10 Jan 2026, 03:29 10 Jan 2026, 00:04 9 Jan 2026, 21:01 9 Jan 2026, 00:04 8 Jan 2026, 21:02 8 Jan 2026, 06:02 8 Jan 2026, 03:29 8 Jan 2026, 00:05 7 Jan 2026, 21:01 7 Jan 2026, 18:02 7 Jan 2026, 09:05 7 Jan 2026, 06:02 7 Jan 2026, 03:30 7 Jan 2026, 00:04 6 Jan 2026, 21:01 6 Jan 2026, 03:29 6 Jan 2026, 00:05 3 Jan 2026, 18:02 27 Dec 2025, 06:02 27 Dec 2025, 03:28 23 Dec 2025, 18:02 20 Dec 2025, 00:04 19 Dec 2025, 21:01 19 Dec 2025, 18:02 19 Dec 2025, 00:05 18 Dec 2025, 21:01 18 Dec 2025, 18:02 18 Dec 2025, 15:02 17 Dec 2025, 15:02 17 Dec 2025, 03:27 16 Dec 2025, 21:01 16 Dec 2025, 18:02 16 Dec 2025, 00:05 15 Dec 2025, 21:01 15 Dec 2025, 18:02 13 Dec 2025, 06:02 12 Dec 2025, 21:01 12 Dec 2025, 00:05 11 Dec 2025, 21:02 11 Dec 2025, 18:01 11 Dec 2025, 06:02 10 Dec 2025, 09:03 9 Dec 2025, 18:01 9 Dec 2025, 06:02 9 Dec 2025, 03:25 8 Dec 2025, 21:01 8 Dec 2025, 06:02 8 Dec 2025, 00:05 6 Dec 2025, 18:02 5 Dec 2025, 00:04 4 Dec 2025, 21:02 4 Dec 2025, 18:02 4 Dec 2025, 06:02 4 Dec 2025, 03:26 3 Dec 2025, 00:04 2 Dec 2025, 21:01 2 Dec 2025, 00:04 1 Dec 2025, 03:31 27 Nov 2025, 06:02 27 Nov 2025, 03:20 26 Nov 2025, 00:04 25 Nov 2025, 03:22 24 Nov 2025, 21:01 21 Nov 2025, 00:04 20 Nov 2025, 18:02 20 Nov 2025, 06:02 20 Nov 2025, 03:20 19 Nov 2025, 03:21 19 Nov 2025, 00:05 18 Nov 2025, 18:02 18 Nov 2025, 09:02 18 Nov 2025, 03:21 17 Nov 2025, 03:24 17 Nov 2025, 00:04 16 Nov 2025, 00:04 14 Nov 2025, 21:26 6 Nov 2025, 18:02 6 Nov 2025, 15:02 6 Nov 2025, 12:02 6 Nov 2025, 06:01 6 Nov 2025, 03:22 4 Nov 2025, 18:02 4 Nov 2025, 03:19 4 Nov 2025, 00:04 3 Nov 2025, 21:01 3 Nov 2025, 12:03 3 Nov 2025, 09:02 3 Nov 2025, 06:02 3 Nov 2025, 03:24 3 Nov 2025, 00:04 2 Nov 2025, 18:01 2 Nov 2025, 12:02 2 Nov 2025, 09:01 1 Nov 2025, 21:01 31 Oct 2025, 00:04 30 Oct 2025, 18:02 29 Oct 2025, 21:02 28 Oct 2025, 18:02 27 Oct 2025, 18:02 24 Oct 2025, 21:01 23 Oct 2025, 21:02 23 Oct 2025, 09:02 23 Oct 2025, 06:02 23 Oct 2025, 00:04 21 Oct 2025, 00:04 20 Oct 2025, 21:02 20 Oct 2025, 15:12 20 Oct 2025, 00:05 17 Oct 2025, 18:01 17 Oct 2025, 12:03 16 Oct 2025, 18:02 16 Oct 2025, 00:05 15 Oct 2025, 18:02 13 Oct 2025, 21:01 12 Oct 2025, 18:01
16 Apr 2026, 21:13
12 May 2026, 16:02 12 May 2026, 14:59 12 May 2026, 01:59 12 May 2026, 00:01 11 May 2026, 23:00 11 May 2026, 21:57 11 May 2026, 20:02 11 May 2026, 18:59 11 May 2026, 18:00 11 May 2026, 15:00 10 May 2026, 23:03 10 May 2026, 17:00 10 May 2026, 04:02 9 May 2026, 04:57 9 May 2026, 04:01 9 May 2026, 03:01 8 May 2026, 22:00 8 May 2026, 19:00 8 May 2026, 18:00 8 May 2026, 16:57 8 May 2026, 07:02 8 May 2026, 06:02 8 May 2026, 03:01 8 May 2026, 02:03 8 May 2026, 01:02 8 May 2026, 00:02 7 May 2026, 22:59 7 May 2026, 21:57 7 May 2026, 17:08 5 May 2026, 23:00 5 May 2026, 21:00 5 May 2026, 17:00 5 May 2026, 15:59 5 May 2026, 14:57 5 May 2026, 00:02 4 May 2026, 22:58 4 May 2026, 22:01 4 May 2026, 18:58 4 May 2026, 15:35 4 May 2026, 06:55 4 May 2026, 04:18 2 May 2026, 18:14 2 May 2026, 04:05 2 May 2026, 00:19 1 May 2026, 18:19 1 May 2026, 04:22 1 May 2026, 00:20 29 Apr 2026, 21:21 29 Apr 2026, 15:36 29 Apr 2026, 09:39 29 Apr 2026, 04:11 29 Apr 2026, 00:20 28 Apr 2026, 21:21 28 Apr 2026, 18:28 28 Apr 2026, 15:45 28 Apr 2026, 06:49 27 Apr 2026, 21:20 27 Apr 2026, 18:23 26 Apr 2026, 04:08 25 Apr 2026, 21:10 24 Apr 2026, 18:11 24 Apr 2026, 06:34 24 Apr 2026, 00:17 23 Apr 2026, 18:19 23 Apr 2026, 04:04 23 Apr 2026, 00:17 22 Apr 2026, 21:15 22 Apr 2026, 04:00 22 Apr 2026, 00:13 21 Apr 2026, 21:14 21 Apr 2026, 09:30 21 Apr 2026, 04:01 20 Apr 2026, 21:14 20 Apr 2026, 18:16 18 Apr 2026, 18:09 18 Apr 2026, 00:13 17 Apr 2026, 21:13 17 Apr 2026, 18:14 17 Apr 2026, 00:15 16 Apr 2026, 21:13 16 Apr 2026, 18:21 16 Apr 2026, 15:30 16 Apr 2026, 04:02 16 Apr 2026, 00:16 15 Apr 2026, 18:20 15 Apr 2026, 15:24 15 Apr 2026, 09:29 15 Apr 2026, 04:00 14 Apr 2026, 21:14 14 Apr 2026, 18:21 14 Apr 2026, 06:32 14 Apr 2026, 04:00 14 Apr 2026, 00:16 13 Apr 2026, 21:14 13 Apr 2026, 18:21 11 Apr 2026, 00:11 10 Apr 2026, 21:09 10 Apr 2026, 18:13 10 Apr 2026, 06:32 10 Apr 2026, 00:12 9 Apr 2026, 21:14 9 Apr 2026, 18:17 9 Apr 2026, 15:29 9 Apr 2026, 03:55 9 Apr 2026, 00:09 8 Apr 2026, 21:13 8 Apr 2026, 18:21 8 Apr 2026, 15:27 8 Apr 2026, 00:12 7 Apr 2026, 21:14 4 Apr 2026, 18:05 4 Apr 2026, 03:46 4 Apr 2026, 00:09 3 Apr 2026, 21:07 3 Apr 2026, 18:08 3 Apr 2026, 03:54 3 Apr 2026, 00:11 2 Apr 2026, 21:08 2 Apr 2026, 18:12 2 Apr 2026, 09:19 2 Apr 2026, 06:21 2 Apr 2026, 03:53 1 Apr 2026, 21:12 1 Apr 2026, 18:13 1 Apr 2026, 04:00 1 Apr 2026, 00:11 31 Mar 2026, 21:09 31 Mar 2026, 06:24 31 Mar 2026, 03:56 31 Mar 2026, 00:11 30 Mar 2026, 21:13 30 Mar 2026, 18:15 28 Mar 2026, 18:04 28 Mar 2026, 15:06 27 Mar 2026, 21:09 27 Mar 2026, 18:14 27 Mar 2026, 15:15 27 Mar 2026, 06:21 27 Mar 2026, 03:56 27 Mar 2026, 00:10 26 Mar 2026, 21:07 26 Mar 2026, 18:16 26 Mar 2026, 15:25 26 Mar 2026, 06:21 26 Mar 2026, 03:55 26 Mar 2026, 00:10 25 Mar 2026, 21:08 25 Mar 2026, 18:15 25 Mar 2026, 06:18 25 Mar 2026, 03:47 25 Mar 2026, 00:08 24 Mar 2026, 18:15 24 Mar 2026, 00:07 23 Mar 2026, 21:08 23 Mar 2026, 18:13 23 Mar 2026, 00:09 22 Mar 2026, 18:04 22 Mar 2026, 00:07 21 Mar 2026, 18:03 21 Mar 2026, 00:07 20 Mar 2026, 21:05 20 Mar 2026, 18:08 20 Mar 2026, 15:13 20 Mar 2026, 03:45 20 Mar 2026, 00:08 19 Mar 2026, 06:17 19 Mar 2026, 00:08 18 Mar 2026, 18:16 18 Mar 2026, 12:11 18 Mar 2026, 09:15 18 Mar 2026, 03:50 18 Mar 2026, 00:09 17 Mar 2026, 21:10 17 Mar 2026, 18:15 17 Mar 2026, 03:46 17 Mar 2026, 00:08 16 Mar 2026, 21:10 16 Mar 2026, 18:15 14 Mar 2026, 03:44 14 Mar 2026, 00:08 13 Mar 2026, 21:07 13 Mar 2026, 18:07 13 Mar 2026, 06:12 12 Mar 2026, 21:07 12 Mar 2026, 18:12 12 Mar 2026, 00:07 11 Mar 2026, 03:43 11 Mar 2026, 00:05 10 Mar 2026, 03:43 10 Mar 2026, 00:05 9 Mar 2026, 21:06 7 Mar 2026, 03:37 7 Mar 2026, 00:07 6 Mar 2026, 06:10 6 Mar 2026, 03:44 6 Mar 2026, 00:12 5 Mar 2026, 06:12 5 Mar 2026, 03:45 5 Mar 2026, 00:07 4 Mar 2026, 21:06 4 Mar 2026, 18:09 4 Mar 2026, 09:09 1 Mar 2026, 06:10 1 Mar 2026, 03:49 28 Feb 2026, 21:01 28 Feb 2026, 00:05 27 Feb 2026, 21:05 27 Feb 2026, 18:07 27 Feb 2026, 09:11 27 Feb 2026, 06:13 27 Feb 2026, 00:08 26 Feb 2026, 21:08 26 Feb 2026, 18:12 26 Feb 2026, 09:14 26 Feb 2026, 06:17 26 Feb 2026, 00:07 25 Feb 2026, 03:47 25 Feb 2026, 00:09 24 Feb 2026, 21:08 24 Feb 2026, 18:15 23 Feb 2026, 21:13 21 Feb 2026, 18:03 21 Feb 2026, 06:08 20 Feb 2026, 21:03 20 Feb 2026, 06:14 20 Feb 2026, 00:07 19 Feb 2026, 21:06 19 Feb 2026, 03:48 19 Feb 2026, 00:08 18 Feb 2026, 03:48 17 Feb 2026, 21:08 17 Feb 2026, 00:08 16 Feb 2026, 21:05 14 Feb 2026, 03:44 13 Feb 2026, 21:09 12 Feb 2026, 00:06 11 Feb 2026, 21:10 11 Feb 2026, 00:11 10 Feb 2026, 21:13 10 Feb 2026, 03:56 10 Feb 2026, 00:11 9 Feb 2026, 15:17 9 Feb 2026, 00:08 7 Feb 2026, 21:05 7 Feb 2026, 18:03 7 Feb 2026, 03:43 6 Feb 2026, 21:06 6 Feb 2026, 00:05 5 Feb 2026, 21:06 5 Feb 2026, 18:13 5 Feb 2026, 03:46 5 Feb 2026, 00:07 4 Feb 2026, 21:07 4 Feb 2026, 18:11 4 Feb 2026, 03:45 4 Feb 2026, 00:06 3 Feb 2026, 21:08 3 Feb 2026, 18:14 3 Feb 2026, 09:10 3 Feb 2026, 03:46 1 Feb 2026, 21:03 1 Feb 2026, 18:02 31 Jan 2026, 03:42 31 Jan 2026, 00:06 30 Jan 2026, 18:07 30 Jan 2026, 00:06 29 Jan 2026, 21:03 28 Jan 2026, 15:06 28 Jan 2026, 03:30 28 Jan 2026, 00:05 27 Jan 2026, 21:01 27 Jan 2026, 18:03 27 Jan 2026, 06:02 26 Jan 2026, 21:03 25 Jan 2026, 03:34 24 Jan 2026, 03:29 23 Jan 2026, 21:01 23 Jan 2026, 18:02 23 Jan 2026, 00:05 22 Jan 2026, 21:03 22 Jan 2026, 15:05 22 Jan 2026, 03:31 22 Jan 2026, 00:05 21 Jan 2026, 21:05 21 Jan 2026, 06:02 21 Jan 2026, 03:30 21 Jan 2026, 00:05 20 Jan 2026, 21:03 20 Jan 2026, 18:03 20 Jan 2026, 15:05 20 Jan 2026, 03:30 19 Jan 2026, 21:01 19 Jan 2026, 00:05 16 Jan 2026, 21:01 16 Jan 2026, 18:02 16 Jan 2026, 15:02 16 Jan 2026, 00:05 14 Jan 2026, 06:02 14 Jan 2026, 00:05 12 Jan 2026, 21:02 12 Jan 2026, 18:02 12 Jan 2026, 00:05 11 Jan 2026, 18:02 11 Jan 2026, 03:31 11 Jan 2026, 00:06 10 Jan 2026, 21:01 10 Jan 2026, 03:29 10 Jan 2026, 00:04 9 Jan 2026, 21:01 9 Jan 2026, 00:04 8 Jan 2026, 21:02 8 Jan 2026, 06:02 8 Jan 2026, 03:29 8 Jan 2026, 00:05 7 Jan 2026, 21:01 7 Jan 2026, 18:02 7 Jan 2026, 09:05 7 Jan 2026, 06:02 7 Jan 2026, 03:30 7 Jan 2026, 00:04 6 Jan 2026, 21:01 6 Jan 2026, 03:29 6 Jan 2026, 00:05 3 Jan 2026, 18:02 27 Dec 2025, 06:02 27 Dec 2025, 03:28 23 Dec 2025, 18:02 20 Dec 2025, 00:04 19 Dec 2025, 21:01 19 Dec 2025, 18:02 19 Dec 2025, 00:05 18 Dec 2025, 21:01 18 Dec 2025, 18:02 18 Dec 2025, 15:02 17 Dec 2025, 15:02 17 Dec 2025, 03:27 16 Dec 2025, 21:01 16 Dec 2025, 18:02 16 Dec 2025, 00:05 15 Dec 2025, 21:01 15 Dec 2025, 18:02 13 Dec 2025, 06:02 12 Dec 2025, 21:01 12 Dec 2025, 00:05 11 Dec 2025, 21:02 11 Dec 2025, 18:01 11 Dec 2025, 06:02 10 Dec 2025, 09:03 9 Dec 2025, 18:01 9 Dec 2025, 06:02 9 Dec 2025, 03:25 8 Dec 2025, 21:01 8 Dec 2025, 06:02 8 Dec 2025, 00:05 6 Dec 2025, 18:02 5 Dec 2025, 00:04 4 Dec 2025, 21:02 4 Dec 2025, 18:02 4 Dec 2025, 06:02 4 Dec 2025, 03:26 3 Dec 2025, 00:04 2 Dec 2025, 21:01 2 Dec 2025, 00:04 1 Dec 2025, 03:31 27 Nov 2025, 06:02 27 Nov 2025, 03:20 26 Nov 2025, 00:04 25 Nov 2025, 03:22 24 Nov 2025, 21:01 21 Nov 2025, 00:04 20 Nov 2025, 18:02 20 Nov 2025, 06:02 20 Nov 2025, 03:20 19 Nov 2025, 03:21 19 Nov 2025, 00:05 18 Nov 2025, 18:02 18 Nov 2025, 09:02 18 Nov 2025, 03:21 17 Nov 2025, 03:24 17 Nov 2025, 00:04 16 Nov 2025, 00:04 14 Nov 2025, 21:26 6 Nov 2025, 18:02 6 Nov 2025, 15:02 6 Nov 2025, 12:02 6 Nov 2025, 06:01 6 Nov 2025, 03:22 4 Nov 2025, 18:02 4 Nov 2025, 03:19 4 Nov 2025, 00:04 3 Nov 2025, 21:01 3 Nov 2025, 12:03 3 Nov 2025, 09:02 3 Nov 2025, 06:02 3 Nov 2025, 03:24 3 Nov 2025, 00:04 2 Nov 2025, 18:01 2 Nov 2025, 12:02 2 Nov 2025, 09:01 1 Nov 2025, 21:01 31 Oct 2025, 00:04 30 Oct 2025, 18:02 29 Oct 2025, 21:02 28 Oct 2025, 18:02 27 Oct 2025, 18:02 24 Oct 2025, 21:01 23 Oct 2025, 21:02 23 Oct 2025, 09:02 23 Oct 2025, 06:02 23 Oct 2025, 00:04 21 Oct 2025, 00:04 20 Oct 2025, 21:02 20 Oct 2025, 15:12 20 Oct 2025, 00:05 17 Oct 2025, 18:01 17 Oct 2025, 12:03 16 Oct 2025, 18:02 16 Oct 2025, 00:05 15 Oct 2025, 18:02 13 Oct 2025, 21:01 12 Oct 2025, 18:01
Wed 1 00:11 Wed 1 04:00 Wed 1 18:13 Wed 1 21:12 Thu 2 03:53 Thu 2 06:21 Thu 2 09:19 Thu 2 18:12 Thu 2 21:08 Fri 3 00:11 Fri 3 03:54 Fri 3 18:08 Fri 3 21:07 Sat 4 00:09 Sat 4 03:46 Sat 4 18:05 Tue 7 21:14 Wed 8 00:12 Wed 8 15:27 Wed 8 18:21 Wed 8 21:13 Thu 9 00:09 Thu 9 03:55 Thu 9 15:29 Thu 9 18:17 Thu 9 21:14 Fri 10 00:12 Fri 10 06:32 Fri 10 18:13 Fri 10 21:09 Sat 11 00:11 Mon 13 18:21 Mon 13 21:14 Tue 14 00:16 Tue 14 04:00 Tue 14 06:32 Tue 14 18:21 Tue 14 21:14 Wed 15 04:00 Wed 15 09:29 Wed 15 15:24 Wed 15 18:20 Thu 16 00:16 Thu 16 04:02 Thu 16 15:30 Thu 16 18:21 Thu 16 21:13 Fri 17 00:15 Fri 17 18:14 Fri 17 21:13 Sat 18 00:13 Sat 18 18:09 Mon 20 18:16 Mon 20 21:14 Tue 21 04:01 Tue 21 09:30 Tue 21 21:14 Wed 22 00:13 Wed 22 04:00 Wed 22 21:15 Thu 23 00:17 Thu 23 04:04 Thu 23 18:19 Fri 24 00:17 Fri 24 06:34 Fri 24 18:11 Sat 25 21:10 Sun 26 04:08 Mon 27 18:23 Mon 27 21:20 Tue 28 06:49 Tue 28 15:45 Tue 28 18:28 Tue 28 21:21 Wed 29 00:20 Wed 29 04:11 Wed 29 09:39 Wed 29 15:36 Wed 29 21:21

agent-sdk/custom-tools.md +804 −0 added

Details

1> ## Documentation Index

2> Fetch the complete documentation index at: https://code.claude.com/docs/llms.txt

3> Use this file to discover all available pages before exploring further.

4 

5# Give Claude custom tools

6 

7> Define custom tools with the Claude Agent SDK's in-process MCP server so Claude can call your functions, hit your APIs, and perform domain-specific operations.

8 

9Custom tools extend the Agent SDK by letting you define your own functions that Claude can call during a conversation. Using the SDK's in-process MCP server, you can give Claude access to databases, external APIs, domain-specific logic, or any other capability your application needs.

10 

11This guide covers how to define tools with input schemas and handlers, bundle them into an MCP server, pass them to `query`, and control which tools Claude can access. It also covers error handling, tool annotations, and returning non-text content like images.

12 

13## Quick reference

14 

15| If you want to... | Do this |

16| :------------------------------------------- | :------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |

17| Define a tool | Use [`@tool`](/en/agent-sdk/python#tool) (Python) or [`tool()`](/en/agent-sdk/typescript#tool) (TypeScript) with a name, description, schema, and handler. See [Create a custom tool](#create-a-custom-tool). |

18| Register a tool with Claude | Wrap in `create_sdk_mcp_server` / `createSdkMcpServer` and pass to `mcpServers` in `query()`. See [Call a custom tool](#call-a-custom-tool). |

19| Pre-approve a tool | Add to your allowed tools. See [Configure allowed tools](#configure-allowed-tools). |

20| Remove a built-in tool from Claude's context | Pass a `tools` array listing only the built-ins you want. See [Configure allowed tools](#configure-allowed-tools). |

21| Let Claude call tools in parallel | Set `readOnlyHint: true` on tools with no side effects. See [Add tool annotations](#add-tool-annotations). |

22| Handle errors without stopping the loop | Return `isError: true` instead of throwing. See [Handle errors](#handle-errors). |

23| Return images or files | Use `image` or `resource` blocks in the content array. See [Return images and resources](#return-images-and-resources). |

24| Scale to many tools | Use [tool search](/en/agent-sdk/tool-search) to load tools on demand. |

25 

26## Create a custom tool

27 

28A tool is defined by four parts, passed as arguments to the [`tool()`](/en/agent-sdk/typescript#tool) helper in TypeScript or the [`@tool`](/en/agent-sdk/python#tool) decorator in Python:

29 

30* **Name:** a unique identifier Claude uses to call the tool.

31* **Description:** what the tool does. Claude reads this to decide when to call it.

32* **Input schema:** the arguments Claude must provide. In TypeScript this is always a [Zod schema](https://zod.dev/), and the handler's `args` are typed from it automatically. In Python this is a dict mapping names to types, like `{"latitude": float}`, which the SDK converts to JSON Schema for you. The Python decorator also accepts a full [JSON Schema](https://json-schema.org/understanding-json-schema/about) dict directly when you need enums, ranges, optional fields, or nested objects.

33* **Handler:** the async function that runs when Claude calls the tool. It receives the validated arguments and must return an object with:

34 * `content` (required): an array of result blocks, each with a `type` of `"text"`, `"image"`, or `"resource"`. See [Return images and resources](#return-images-and-resources) for non-text blocks.

35 * `isError` (optional): set to `true` to signal a tool failure so Claude can react to it. See [Handle errors](#handle-errors).

36 

37After defining a tool, wrap it in a server with [`createSdkMcpServer`](/en/agent-sdk/typescript#create-sdk-mcp-server) (TypeScript) or [`create_sdk_mcp_server`](/en/agent-sdk/python#create-sdk-mcp-server) (Python). The server runs in-process inside your application, not as a separate process.

38 

39### Weather tool example

40 

41This example defines a `get_temperature` tool and wraps it in an MCP server. It only sets up the tool; to pass it to `query` and run it, see [Call a custom tool](#call-a-custom-tool) below.

42 

43<CodeGroup>

44 ```python Python theme={null}

45 from typing import Any

46 import httpx

47 from claude_agent_sdk import tool, create_sdk_mcp_server

48 

49 

50 # Define a tool: name, description, input schema, handler

51 @tool(

52 "get_temperature",

53 "Get the current temperature at a location",

54 {"latitude": float, "longitude": float},

55 )

56 async def get_temperature(args: dict[str, Any]) -> dict[str, Any]:

57 async with httpx.AsyncClient() as client:

58 response = await client.get(

59 "https://api.open-meteo.com/v1/forecast",

60 params={

61 "latitude": args["latitude"],

62 "longitude": args["longitude"],

63 "current": "temperature_2m",

64 "temperature_unit": "fahrenheit",

65 },

66 )

67 data = response.json()

68 

69 # Return a content array - Claude sees this as the tool result

70 return {

71 "content": [

72 {

73 "type": "text",

74 "text": f"Temperature: {data['current']['temperature_2m']}°F",

75 }

76 ]

77 }

78 

79 

80 # Wrap the tool in an in-process MCP server

81 weather_server = create_sdk_mcp_server(

82 name="weather",

83 version="1.0.0",

84 tools=[get_temperature],

85 )

86 ```

87 

88 ```typescript TypeScript theme={null}

89 import { tool, createSdkMcpServer } from "@anthropic-ai/claude-agent-sdk";

90 import { z } from "zod";

91 

92 // Define a tool: name, description, input schema, handler

93 const getTemperature = tool(

94 "get_temperature",

95 "Get the current temperature at a location",

96 {

97 latitude: z.number().describe("Latitude coordinate"), // .describe() adds a field description Claude sees

98 longitude: z.number().describe("Longitude coordinate")

99 },

100 async (args) => {

101 // args is typed from the schema: { latitude: number; longitude: number }

102 const response = await fetch(

103 `https://api.open-meteo.com/v1/forecast?latitude=${args.latitude}&longitude=${args.longitude}&current=temperature_2m&temperature_unit=fahrenheit`

104 );

105 const data: any = await response.json();

106 

107 // Return a content array - Claude sees this as the tool result

108 return {

109 content: [{ type: "text", text: `Temperature: ${data.current.temperature_2m}°F` }]

110 };

111 }

112 );

113 

114 // Wrap the tool in an in-process MCP server

115 const weatherServer = createSdkMcpServer({

116 name: "weather",

117 version: "1.0.0",

118 tools: [getTemperature]

119 });

120 ```

121</CodeGroup>

122 

123See the [`tool()`](/en/agent-sdk/typescript#tool) TypeScript reference or the [`@tool`](/en/agent-sdk/python#tool) Python reference for full parameter details, including JSON Schema input formats and return value structure.

124 

125<Tip>

126 To make a parameter optional: in TypeScript, add `.default()` to the Zod field. In Python, the dict schema treats every key as required, so leave the parameter out of the schema, mention it in the description string, and read it with `args.get()` in the handler. The [`get_precipitation_chance` tool below](#add-more-tools) shows both patterns.

127</Tip>

128 

129### Call a custom tool

130 

131Pass the MCP server you created to `query` via the `mcpServers` option. The key in `mcpServers` becomes the `{server_name}` segment in each tool's fully qualified name: `mcp__{server_name}__{tool_name}`. List that name in `allowedTools` so the tool runs without a permission prompt.

132 

133These snippets reuse the `weatherServer` from the [example above](#weather-tool-example) to ask Claude what the weather is in a specific location.

134 

135<CodeGroup>

136 ```python Python theme={null}

137 import asyncio

138 from claude_agent_sdk import query, ClaudeAgentOptions, ResultMessage

139 

140 

141 async def main():

142 options = ClaudeAgentOptions(

143 mcp_servers={"weather": weather_server},

144 allowed_tools=["mcp__weather__get_temperature"],

145 )

146 

147 async for message in query(

148 prompt="What's the temperature in San Francisco?",

149 options=options,

150 ):

151 # ResultMessage is the final message after all tool calls complete

152 if isinstance(message, ResultMessage) and message.subtype == "success":

153 print(message.result)

154 

155 

156 asyncio.run(main())

157 ```

158 

159 ```typescript TypeScript theme={null}

160 import { query } from "@anthropic-ai/claude-agent-sdk";

161 

162 for await (const message of query({

163 prompt: "What's the temperature in San Francisco?",

164 options: {

165 mcpServers: { weather: weatherServer },

166 allowedTools: ["mcp__weather__get_temperature"]

167 }

168 })) {

169 // "result" is the final message after all tool calls complete

170 if (message.type === "result" && message.subtype === "success") {

171 console.log(message.result);

172 }

173 }

174 ```

175</CodeGroup>

176 

177### Add more tools

178 

179A server holds as many tools as you list in its `tools` array. With more than one tool on a server, you can list each one in `allowedTools` individually or use the wildcard `mcp__weather__*` to cover every tool the server exposes.

180 

181The example below adds a second tool, `get_precipitation_chance`, to the `weatherServer` from the [weather tool example](#weather-tool-example) and rebuilds it with both tools in the array.

182 

183<CodeGroup>

184 ```python Python theme={null}

185 # Define a second tool for the same server

186 @tool(

187 "get_precipitation_chance",

188 "Get the hourly precipitation probability for a location. "

189 "Optionally pass 'hours' (1-24) to control how many hours to return.",

190 {"latitude": float, "longitude": float},

191 )

192 async def get_precipitation_chance(args: dict[str, Any]) -> dict[str, Any]:

193 # 'hours' isn't in the schema - read it with .get() to make it optional

194 hours = args.get("hours", 12)

195 async with httpx.AsyncClient() as client:

196 response = await client.get(

197 "https://api.open-meteo.com/v1/forecast",

198 params={

199 "latitude": args["latitude"],

200 "longitude": args["longitude"],

201 "hourly": "precipitation_probability",

202 "forecast_days": 1,

203 },

204 )

205 data = response.json()

206 chances = data["hourly"]["precipitation_probability"][:hours]

207 

208 return {

209 "content": [

210 {

211 "type": "text",

212 "text": f"Next {hours} hours: {'%, '.join(map(str, chances))}%",

213 }

214 ]

215 }

216 

217 

218 # Rebuild the server with both tools in the array

219 weather_server = create_sdk_mcp_server(

220 name="weather",

221 version="1.0.0",

222 tools=[get_temperature, get_precipitation_chance],

223 )

224 ```

225 

226 ```typescript TypeScript theme={null}

227 // Define a second tool for the same server

228 const getPrecipitationChance = tool(

229 "get_precipitation_chance",

230 "Get the hourly precipitation probability for a location",

231 {

232 latitude: z.number(),

233 longitude: z.number(),

234 hours: z

235 .number()

236 .int()

237 .min(1)

238 .max(24)

239 .default(12) // .default() makes the parameter optional

240 .describe("How many hours of forecast to return")

241 },

242 async (args) => {

243 const response = await fetch(

244 `https://api.open-meteo.com/v1/forecast?latitude=${args.latitude}&longitude=${args.longitude}&hourly=precipitation_probability&forecast_days=1`

245 );

246 const data: any = await response.json();

247 const chances = data.hourly.precipitation_probability.slice(0, args.hours);

248 

249 return {

250 content: [{ type: "text", text: `Next ${args.hours} hours: ${chances.join("%, ")}%` }]

251 };

252 }

253 );

254 

255 // Rebuild the server with both tools in the array

256 const weatherServer = createSdkMcpServer({

257 name: "weather",

258 version: "1.0.0",

259 tools: [getTemperature, getPrecipitationChance]

260 });

261 ```

262</CodeGroup>

263 

264Every tool in this array consumes context window space on every turn. If you're defining dozens of tools, see [tool search](/en/agent-sdk/tool-search) to load them on demand instead.

265 

266### Add tool annotations

267 

268[Tool annotations](https://modelcontextprotocol.io/docs/concepts/tools#tool-annotations) are optional metadata describing how a tool behaves. Pass them as the fifth argument to `tool()` helper in TypeScript or via the `annotations` keyword argument for the `@tool` decorator in Python. All hint fields are Booleans.

269 

270| Field | Default | Meaning |

271| :---------------- | :------ | :-------------------------------------------------------------------------------------------------------------------- |

272| `readOnlyHint` | `false` | Tool does not modify its environment. Controls whether the tool can be called in parallel with other read-only tools. |

273| `destructiveHint` | `true` | Tool may perform destructive updates. Informational only. |

274| `idempotentHint` | `false` | Repeated calls with the same arguments have no additional effect. Informational only. |

275| `openWorldHint` | `true` | Tool reaches systems outside your process. Informational only. |

276 

277Annotations are metadata, not enforcement. A tool marked `readOnlyHint: true` can still write to disk if that's what the handler does. Keep the annotation accurate to the handler.

278 

279This example adds `readOnlyHint` to the `get_temperature` tool from the [weather tool example](#weather-tool-example).

280 

281<CodeGroup>

282 ```python Python theme={null}

283 from claude_agent_sdk import tool, ToolAnnotations

284 

285 

286 @tool(

287 "get_temperature",

288 "Get the current temperature at a location",

289 {"latitude": float, "longitude": float},

290 annotations=ToolAnnotations(

291 readOnlyHint=True

292 ), # Lets Claude batch this with other read-only calls

293 )

294 async def get_temperature(args):

295 return {"content": [{"type": "text", "text": "..."}]}

296 ```

297 

298 ```typescript TypeScript theme={null}

299 tool(

300 "get_temperature",

301 "Get the current temperature at a location",

302 { latitude: z.number(), longitude: z.number() },

303 async (args) => ({ content: [{ type: "text", text: `...` }] }),

304 { annotations: { readOnlyHint: true } } // Lets Claude batch this with other read-only calls

305 );

306 ```

307</CodeGroup>

308 

309See `ToolAnnotations` in the [TypeScript](/en/agent-sdk/typescript#tool-annotations) or [Python](/en/agent-sdk/python#tool-annotations) reference.

310 

311## Control tool access

312 

313The [weather tool example](#weather-tool-example) registered a server and listed tools in `allowedTools`. This section covers how tool names are constructed and how to scope access when you have multiple tools or want to restrict built-ins.

314 

315### Tool name format

316 

317When MCP tools are exposed to Claude, their names follow a specific format:

318 

319* Pattern: `mcp__{server_name}__{tool_name}`

320* Example: A tool named `get_temperature` in server `weather` becomes `mcp__weather__get_temperature`

321 

322### Configure allowed tools

323 

324The `tools` option and the allowed/disallowed lists operate on separate layers. `tools` controls which built-in tools appear in Claude's context. Allowed and disallowed tool lists control whether calls are approved or denied once Claude attempts them.

325 

326| Option | Layer | Effect |

327| :------------------------ | :----------- | :------------------------------------------------------------------------------------------------------------------------------------------------ |

328| `tools: ["Read", "Grep"]` | Availability | Only the listed built-ins are in Claude's context. Unlisted built-ins are removed. MCP tools are unaffected. |

329| `tools: []` | Availability | All built-ins are removed. Claude can only use your MCP tools. |

330| allowed tools | Permission | Listed tools run without a permission prompt. Unlisted tools remain available; calls go through the [permission flow](/en/agent-sdk/permissions). |

331| disallowed tools | Permission | Every call to a listed tool is denied. The tool stays in Claude's context, so Claude may still attempt it before the call is rejected. |

332 

333To limit which built-ins Claude can use, prefer `tools` over disallowed tools. Omitting a tool from `tools` removes it from context so Claude never attempts it; listing it in `disallowedTools` (Python: `disallowed_tools`) blocks the call but leaves the tool visible, so Claude may waste a turn trying it. See [Configure permissions](/en/agent-sdk/permissions) for the full evaluation order.

334 

335## Handle errors

336 

337How your handler reports errors determines whether the agent loop continues or stops:

338 

339| What happens | Result |

340| :--------------------------------------------------------------------------------------- | :--------------------------------------------------------------------------------------------------------------- |

341| Handler throws an uncaught exception | Agent loop stops. Claude never sees the error, and the `query` call fails. |

342| Handler catches the error and returns `isError: true` (TS) / `"is_error": True` (Python) | Agent loop continues. Claude sees the error as data and can retry, try a different tool, or explain the failure. |

343 

344The example below catches two kinds of failures inside the handler instead of letting them throw. A non-200 HTTP status is caught from the response and returned as an error result. A network error or invalid JSON is caught by the surrounding `try/except` (Python) or `try/catch` (TypeScript) and also returned as an error result. In both cases the handler returns normally and the agent loop continues.

345 

346<CodeGroup>

347 ```python Python theme={null}

348 import json

349 import httpx

350 from typing import Any

351 

352 

353 @tool(

354 "fetch_data",

355 "Fetch data from an API",

356 {"endpoint": str}, # Simple schema

357 )

358 async def fetch_data(args: dict[str, Any]) -> dict[str, Any]:

359 try:

360 async with httpx.AsyncClient() as client:

361 response = await client.get(args["endpoint"])

362 if response.status_code != 200:

363 # Return the failure as a tool result so Claude can react to it.

364 # is_error marks this as a failed call rather than odd-looking data.

365 return {

366 "content": [

367 {

368 "type": "text",

369 "text": f"API error: {response.status_code} {response.reason_phrase}",

370 }

371 ],

372 "is_error": True,

373 }

374 

375 data = response.json()

376 return {"content": [{"type": "text", "text": json.dumps(data, indent=2)}]}

377 except Exception as e:

378 # Catching here keeps the agent loop alive. An uncaught exception

379 # would end the whole query() call.

380 return {

381 "content": [{"type": "text", "text": f"Failed to fetch data: {str(e)}"}],

382 "is_error": True,

383 }

384 ```

385 

386 ```typescript TypeScript theme={null}

387 tool(

388 "fetch_data",

389 "Fetch data from an API",

390 {

391 endpoint: z.string().url().describe("API endpoint URL")

392 },

393 async (args) => {

394 try {

395 const response = await fetch(args.endpoint);

396 

397 if (!response.ok) {

398 // Return the failure as a tool result so Claude can react to it.

399 // isError marks this as a failed call rather than odd-looking data.

400 return {

401 content: [

402 {

403 type: "text",

404 text: `API error: ${response.status} ${response.statusText}`

405 }

406 ],

407 isError: true

408 };

409 }

410 

411 const data = await response.json();

412 return {

413 content: [

414 {

415 type: "text",

416 text: JSON.stringify(data, null, 2)

417 }

418 ]

419 };

420 } catch (error) {

421 // Catching here keeps the agent loop alive. An uncaught throw

422 // would end the whole query() call.

423 return {

424 content: [

425 {

426 type: "text",

427 text: `Failed to fetch data: ${error instanceof Error ? error.message : String(error)}`

428 }

429 ],

430 isError: true

431 };

432 }

433 }

434 );

435 ```

436</CodeGroup>

437 

438## Return images and resources

439 

440The `content` array in a tool result accepts `text`, `image`, and `resource` blocks. You can mix them in the same response.

441 

442### Images

443 

444An image block carries the image bytes inline, encoded as base64. There is no URL field. To return an image that lives at a URL, fetch it in the handler, read the response bytes, and base64-encode them before returning. The result is processed as visual input.

445 

446| Field | Type | Notes |

447| :--------- | :-------- | :------------------------------------------------------------------------- |

448| `type` | `"image"` | |

449| `data` | `string` | Base64-encoded bytes. Raw base64 only, no `data:image/...;base64,` prefix |

450| `mimeType` | `string` | Required. For example `image/png`, `image/jpeg`, `image/webp`, `image/gif` |

451 

452<CodeGroup>

453 ```python Python theme={null}

454 import base64

455 import httpx

456 

457 

458 # Define a tool that fetches an image from a URL and returns it to Claude

459 @tool("fetch_image", "Fetch an image from a URL and return it to Claude", {"url": str})

460 async def fetch_image(args):

461 async with httpx.AsyncClient() as client: # Fetch the image bytes

462 response = await client.get(args["url"])

463 

464 return {

465 "content": [

466 {

467 "type": "image",

468 "data": base64.b64encode(response.content).decode(

469 "ascii"

470 ), # Base64-encode the raw bytes

471 "mimeType": response.headers.get(

472 "content-type", "image/png"

473 ), # Read MIME type from the response

474 }

475 ]

476 }

477 ```

478 

479 ```typescript TypeScript theme={null}

480 tool(

481 "fetch_image",

482 "Fetch an image from a URL and return it to Claude",

483 {

484 url: z.string().url()

485 },

486 async (args) => {

487 const response = await fetch(args.url); // Fetch the image bytes

488 const buffer = Buffer.from(await response.arrayBuffer()); // Read into a Buffer for base64 encoding

489 const mimeType = response.headers.get("content-type") ?? "image/png";

490 

491 return {

492 content: [

493 {

494 type: "image",

495 data: buffer.toString("base64"), // Base64-encode the raw bytes

496 mimeType

497 }

498 ]

499 };

500 }

501 );

502 ```

503</CodeGroup>

504 

505### Resources

506 

507A resource block embeds a piece of content identified by a URI. The URI is a label for Claude to reference; the actual content rides in the block's `text` or `blob` field. Use this when your tool produces something that makes sense to address by name later, such as a generated file or a record from an external system.

508 

509| Field | Type | Notes |

510| :------------------ | :----------- | :---------------------------------------------------------- |

511| `type` | `"resource"` | |

512| `resource.uri` | `string` | Identifier for the content. Any URI scheme |

513| `resource.text` | `string` | The content, if it's text. Provide this or `blob`, not both |

514| `resource.blob` | `string` | The content base64-encoded, if it's binary |

515| `resource.mimeType` | `string` | Optional |

516 

517This example shows a resource block returned from inside a tool handler. The URI `file:///tmp/report.md` is a label that Claude can reference later; the SDK does not read from that path.

518 

519<CodeGroup>

520 ```typescript TypeScript theme={null}

521 return {

522 content: [

523 {

524 type: "resource",

525 resource: {

526 uri: "file:///tmp/report.md", // Label for Claude to reference, not a path the SDK reads

527 mimeType: "text/markdown",

528 text: "# Report\n..." // The actual content, inline

529 }

530 }

531 ]

532 };

533 ```

534 

535 ```python Python theme={null}

536 return {

537 "content": [

538 {

539 "type": "resource",

540 "resource": {

541 "uri": "file:///tmp/report.md", # Label for Claude to reference, not a path the SDK reads

542 "mimeType": "text/markdown",

543 "text": "# Report\n...", # The actual content, inline

544 },

545 }

546 ]

547 }

548 ```

549</CodeGroup>

550 

551These block shapes come from the MCP `CallToolResult` type. See the [MCP specification](https://modelcontextprotocol.io/specification/2025-06-18/server/tools#tool-result) for the full definition.

552 

553## Example: unit converter

554 

555This tool converts values between units of length, temperature, and weight. A user can ask "convert 100 kilometers to miles" or "what is 72°F in Celsius," and Claude picks the right unit type and units from the request.

556 

557It demonstrates two patterns:

558 

559* **Enum schemas:** `unit_type` is constrained to a fixed set of values. In TypeScript, use `z.enum()`. In Python, the dict schema doesn't support enums, so the full JSON Schema dict is required.

560* **Unsupported input handling:** when a conversion pair isn't found, the handler returns `isError: true` so Claude can tell the user what went wrong rather than treating a failure as a normal result.

561 

562<CodeGroup>

563 ```python Python theme={null}

564 from typing import Any

565 from claude_agent_sdk import tool, create_sdk_mcp_server

566 

567 

568 # z.enum() in TypeScript becomes an "enum" constraint in JSON Schema.

569 # The dict schema has no equivalent, so full JSON Schema is required.

570 @tool(

571 "convert_units",

572 "Convert a value from one unit to another",

573 {

574 "type": "object",

575 "properties": {

576 "unit_type": {

577 "type": "string",

578 "enum": ["length", "temperature", "weight"],

579 "description": "Category of unit",

580 },

581 "from_unit": {

582 "type": "string",

583 "description": "Unit to convert from, e.g. kilometers, fahrenheit, pounds",

584 },

585 "to_unit": {"type": "string", "description": "Unit to convert to"},

586 "value": {"type": "number", "description": "Value to convert"},

587 },

588 "required": ["unit_type", "from_unit", "to_unit", "value"],

589 },

590 )

591 async def convert_units(args: dict[str, Any]) -> dict[str, Any]:

592 conversions = {

593 "length": {

594 "kilometers_to_miles": lambda v: v * 0.621371,

595 "miles_to_kilometers": lambda v: v * 1.60934,

596 "meters_to_feet": lambda v: v * 3.28084,

597 "feet_to_meters": lambda v: v * 0.3048,

598 },

599 "temperature": {

600 "celsius_to_fahrenheit": lambda v: (v * 9) / 5 + 32,

601 "fahrenheit_to_celsius": lambda v: (v - 32) * 5 / 9,

602 "celsius_to_kelvin": lambda v: v + 273.15,

603 "kelvin_to_celsius": lambda v: v - 273.15,

604 },

605 "weight": {

606 "kilograms_to_pounds": lambda v: v * 2.20462,

607 "pounds_to_kilograms": lambda v: v * 0.453592,

608 "grams_to_ounces": lambda v: v * 0.035274,

609 "ounces_to_grams": lambda v: v * 28.3495,

610 },

611 }

612 

613 key = f"{args['from_unit']}_to_{args['to_unit']}"

614 fn = conversions.get(args["unit_type"], {}).get(key)

615 

616 if not fn:

617 return {

618 "content": [

619 {

620 "type": "text",

621 "text": f"Unsupported conversion: {args['from_unit']} to {args['to_unit']}",

622 }

623 ],

624 "is_error": True,

625 }

626 

627 result = fn(args["value"])

628 return {

629 "content": [

630 {

631 "type": "text",

632 "text": f"{args['value']} {args['from_unit']} = {result:.4f} {args['to_unit']}",

633 }

634 ]

635 }

636 

637 

638 converter_server = create_sdk_mcp_server(

639 name="converter",

640 version="1.0.0",

641 tools=[convert_units],

642 )

643 ```

644 

645 ```typescript TypeScript theme={null}

646 import { tool, createSdkMcpServer } from "@anthropic-ai/claude-agent-sdk";

647 import { z } from "zod";

648 

649 const convert = tool(

650 "convert_units",

651 "Convert a value from one unit to another",

652 {

653 unit_type: z.enum(["length", "temperature", "weight"]).describe("Category of unit"),

654 from_unit: z

655 .string()

656 .describe("Unit to convert from, e.g. kilometers, fahrenheit, pounds"),

657 to_unit: z.string().describe("Unit to convert to"),

658 value: z.number().describe("Value to convert")

659 },

660 async (args) => {

661 type Conversions = Record<string, Record<string, (v: number) => number>>;

662 

663 const conversions: Conversions = {

664 length: {

665 kilometers_to_miles: (v) => v * 0.621371,

666 miles_to_kilometers: (v) => v * 1.60934,

667 meters_to_feet: (v) => v * 3.28084,

668 feet_to_meters: (v) => v * 0.3048

669 },

670 temperature: {

671 celsius_to_fahrenheit: (v) => (v * 9) / 5 + 32,

672 fahrenheit_to_celsius: (v) => ((v - 32) * 5) / 9,

673 celsius_to_kelvin: (v) => v + 273.15,

674 kelvin_to_celsius: (v) => v - 273.15

675 },

676 weight: {

677 kilograms_to_pounds: (v) => v * 2.20462,

678 pounds_to_kilograms: (v) => v * 0.453592,

679 grams_to_ounces: (v) => v * 0.035274,

680 ounces_to_grams: (v) => v * 28.3495

681 }

682 };

683 

684 const key = `${args.from_unit}_to_${args.to_unit}`;

685 const fn = conversions[args.unit_type]?.[key];

686 

687 if (!fn) {

688 return {

689 content: [

690 {

691 type: "text",

692 text: `Unsupported conversion: ${args.from_unit} to ${args.to_unit}`

693 }

694 ],

695 isError: true

696 };

697 }

698 

699 const result = fn(args.value);

700 return {

701 content: [

702 {

703 type: "text",

704 text: `${args.value} ${args.from_unit} = ${result.toFixed(4)} ${args.to_unit}`

705 }

706 ]

707 };

708 }

709 );

710 

711 const converterServer = createSdkMcpServer({

712 name: "converter",

713 version: "1.0.0",

714 tools: [convert]

715 });

716 ```

717</CodeGroup>

718 

719Once the server is defined, pass it to `query` the same way as the weather example. This example sends three different prompts in a loop to show the same tool handling different unit types. For each response, it inspects `AssistantMessage` objects (which contain the tool calls Claude made during that turn) and prints each `ToolUseBlock` before printing the final `ResultMessage` text. This lets you see when Claude is using the tool versus answering from its own knowledge.

720 

721<CodeGroup>

722 ```python Python theme={null}

723 import asyncio

724 from claude_agent_sdk import (

725 query,

726 ClaudeAgentOptions,

727 ResultMessage,

728 AssistantMessage,

729 ToolUseBlock,

730 )

731 

732 

733 async def main():

734 options = ClaudeAgentOptions(

735 mcp_servers={"converter": converter_server},

736 allowed_tools=["mcp__converter__convert_units"],

737 )

738 

739 prompts = [

740 "Convert 100 kilometers to miles.",

741 "What is 72°F in Celsius?",

742 "How many pounds is 5 kilograms?",

743 ]

744 

745 for prompt in prompts:

746 async for message in query(prompt=prompt, options=options):

747 if isinstance(message, AssistantMessage):

748 for block in message.content:

749 if isinstance(block, ToolUseBlock):

750 print(f"[tool call] {block.name}({block.input})")

751 elif isinstance(message, ResultMessage) and message.subtype == "success":

752 print(f"Q: {prompt}\nA: {message.result}\n")

753 

754 

755 asyncio.run(main())

756 ```

757 

758 ```typescript TypeScript theme={null}

759 import { query } from "@anthropic-ai/claude-agent-sdk";

760 

761 const prompts = [

762 "Convert 100 kilometers to miles.",

763 "What is 72°F in Celsius?",

764 "How many pounds is 5 kilograms?"

765 ];

766 

767 for (const prompt of prompts) {

768 for await (const message of query({

769 prompt,

770 options: {

771 mcpServers: { converter: converterServer },

772 allowedTools: ["mcp__converter__convert_units"]

773 }

774 })) {

775 if (message.type === "assistant") {

776 for (const block of message.message.content) {

777 if (block.type === "tool_use") {

778 console.log(`[tool call] ${block.name}`, block.input);

779 }

780 }

781 } else if (message.type === "result" && message.subtype === "success") {

782 console.log(`Q: ${prompt}\nA: ${message.result}\n`);

783 }

784 }

785 }

786 ```

787</CodeGroup>

788 

789## Next steps

790 

791Custom tools wrap async functions in a standard interface. You can mix the patterns on this page in the same server: a single server can hold a database tool, an API gateway tool, and an image renderer alongside each other.

792 

793From here:

794 

795* If your server grows to dozens of tools, see [tool search](/en/agent-sdk/tool-search) to defer loading them until Claude needs them.

796* To connect to external MCP servers (filesystem, GitHub, Slack) instead of building your own, see [Connect MCP servers](/en/agent-sdk/mcp).

797* To control which tools run automatically versus requiring approval, see [Configure permissions](/en/agent-sdk/permissions).

798 

799## Related documentation

800 

801* [TypeScript SDK Reference](/en/agent-sdk/typescript)

802* [Python SDK Reference](/en/agent-sdk/python)

803* [MCP Documentation](https://modelcontextprotocol.io)

804* [SDK Overview](/en/agent-sdk/overview)