1
1
import { type CallToolResult } from '@modelcontextprotocol/sdk/types.js'
2
2
import { z } from 'zod'
3
3
4
- import {
5
- handleKVNamespaceCreate ,
6
- handleKVNamespaceDelete ,
7
- handleKVNamespaceGet ,
8
- handleKVNamespacesList ,
9
- handleKVNamespaceUpdate ,
10
- } from '../api/kv'
11
4
import { getCloudflareClient } from '../cloudflare-api'
12
5
import { type CloudflareMcpAgent } from '../types/cloudflare-mcp-agent'
6
+ import {
7
+ KvNamespaceIdSchema ,
8
+ KvNamespacesListParamsSchema ,
9
+ KvNamespaceTitleSchema ,
10
+ } from '../types/kv_namespace'
13
11
14
- const kvNamespaceTitle = z . string ( ) . describe ( 'The title of the kv namespace' )
15
- const kvNamespaceId = z . string ( ) . describe ( 'The id of the kv namespace' )
12
+ // Define the standard response for missing account ID
16
13
const MISSING_ACCOUNT_ID_RESPONSE = {
17
14
content : [
18
15
{
@@ -23,21 +20,27 @@ const MISSING_ACCOUNT_ID_RESPONSE = {
23
20
} satisfies CallToolResult
24
21
25
22
export function registerKVTools ( agent : CloudflareMcpAgent ) {
23
+ /**
24
+ * Tool to list KV namespaces.
25
+ */
26
26
agent . server . tool (
27
27
'kv_namespaces_list' ,
28
28
'List all of the kv namespaces in your Cloudflare account' ,
29
- { } ,
30
- async ( ) => {
29
+ { params : KvNamespacesListParamsSchema . optional ( ) } ,
30
+ async ( { params } ) => {
31
31
const account_id = agent . getActiveAccountId ( )
32
32
if ( ! account_id ) {
33
33
return MISSING_ACCOUNT_ID_RESPONSE
34
34
}
35
35
try {
36
- const namespaces = await handleKVNamespacesList ( {
37
- client : getCloudflareClient ( agent . props . accessToken ) ,
36
+ const client = getCloudflareClient ( agent . props . accessToken )
37
+ const response = await client . kv . namespaces . list ( {
38
38
account_id,
39
+ ...params ,
39
40
} )
40
41
42
+ const namespaces = response . result ?? [ ]
43
+
41
44
return {
42
45
content : [
43
46
{
@@ -54,29 +57,31 @@ export function registerKVTools(agent: CloudflareMcpAgent) {
54
57
content : [
55
58
{
56
59
type : 'text' ,
57
- text : `Error listing KV namespaces: ${ error instanceof Error && error . message } ` ,
60
+ text : `Error listing KV namespaces: ${ error instanceof Error ? error . message : String ( error ) } ` ,
58
61
} ,
59
62
] ,
60
63
}
61
64
}
62
65
}
63
66
)
64
67
68
+ /**
69
+ * Tool to create a KV namespace.
70
+ */
65
71
agent . server . tool (
66
72
'kv_namespace_create' ,
67
73
'Create a new kv namespace in your Cloudflare account' ,
68
- { title : kvNamespaceTitle } ,
74
+ {
75
+ title : KvNamespaceTitleSchema ,
76
+ } ,
69
77
async ( { title } ) => {
70
78
const account_id = agent . getActiveAccountId ( )
71
79
if ( ! account_id ) {
72
80
return MISSING_ACCOUNT_ID_RESPONSE
73
81
}
74
82
try {
75
- const namespace = await handleKVNamespaceCreate ( {
76
- client : getCloudflareClient ( agent . props . accessToken ) ,
77
- account_id,
78
- title : title ,
79
- } )
83
+ const client = getCloudflareClient ( agent . props . accessToken )
84
+ const namespace = await client . kv . namespaces . create ( { account_id, title } )
80
85
return {
81
86
content : [
82
87
{
@@ -90,34 +95,36 @@ export function registerKVTools(agent: CloudflareMcpAgent) {
90
95
content : [
91
96
{
92
97
type : 'text' ,
93
- text : `Error creating KV namespace: ${ error instanceof Error && error . message } ` ,
98
+ text : `Error creating KV namespace: ${ error instanceof Error ? error . message : String ( error ) } ` ,
94
99
} ,
95
100
] ,
96
101
}
97
102
}
98
103
}
99
104
)
100
105
106
+ /**
107
+ * Tool to delete a KV namespace.
108
+ */
101
109
agent . server . tool (
102
110
'kv_namespace_delete' ,
103
111
'Delete a kv namespace in your Cloudflare account' ,
104
- { namespace_id : kvNamespaceId } ,
112
+ {
113
+ namespace_id : KvNamespaceIdSchema ,
114
+ } ,
105
115
async ( { namespace_id } ) => {
106
116
const account_id = agent . getActiveAccountId ( )
107
117
if ( ! account_id ) {
108
118
return MISSING_ACCOUNT_ID_RESPONSE
109
119
}
110
120
try {
111
- const namespace = await handleKVNamespaceDelete ( {
112
- client : getCloudflareClient ( agent . props . accessToken ) ,
113
- account_id,
114
- namespace_id,
115
- } )
121
+ const client = getCloudflareClient ( agent . props . accessToken )
122
+ const result = await client . kv . namespaces . delete ( namespace_id , { account_id } )
116
123
return {
117
124
content : [
118
125
{
119
126
type : 'text' ,
120
- text : JSON . stringify ( namespace ) ,
127
+ text : JSON . stringify ( result ?? { success : true } ) ,
121
128
} ,
122
129
] ,
123
130
}
@@ -126,29 +133,31 @@ export function registerKVTools(agent: CloudflareMcpAgent) {
126
133
content : [
127
134
{
128
135
type : 'text' ,
129
- text : `Error deleting KV namespace: ${ error instanceof Error && error . message } ` ,
136
+ text : `Error deleting KV namespace: ${ error instanceof Error ? error . message : String ( error ) } ` ,
130
137
} ,
131
138
] ,
132
139
}
133
140
}
134
141
}
135
142
)
136
143
144
+ /**
145
+ * Tool to get details of a specific KV namespace.
146
+ */
137
147
agent . server . tool (
138
148
'kv_namespace_get' ,
139
- 'Get a kv namespace in your Cloudflare account' ,
140
- { namespace_id : kvNamespaceId } ,
149
+ 'Get details of a kv namespace in your Cloudflare account' ,
150
+ {
151
+ namespace_id : KvNamespaceIdSchema ,
152
+ } ,
141
153
async ( { namespace_id } ) => {
142
154
const account_id = agent . getActiveAccountId ( )
143
155
if ( ! account_id ) {
144
156
return MISSING_ACCOUNT_ID_RESPONSE
145
157
}
146
158
try {
147
- const namespace = await handleKVNamespaceGet ( {
148
- client : getCloudflareClient ( agent . props . accessToken ) ,
149
- account_id,
150
- namespace_id,
151
- } )
159
+ const client = getCloudflareClient ( agent . props . accessToken )
160
+ const namespace = await client . kv . namespaces . get ( namespace_id , { account_id } )
152
161
return {
153
162
content : [
154
163
{
@@ -162,38 +171,40 @@ export function registerKVTools(agent: CloudflareMcpAgent) {
162
171
content : [
163
172
{
164
173
type : 'text' ,
165
- text : `Error getting KV namespace: ${ error instanceof Error && error . message } ` ,
174
+ text : `Error getting KV namespace: ${ error instanceof Error ? error . message : String ( error ) } ` ,
166
175
} ,
167
176
] ,
168
177
}
169
178
}
170
179
}
171
180
)
172
181
182
+ /**
183
+ * Tool to update the title of a KV namespace.
184
+ */
173
185
agent . server . tool (
174
186
'kv_namespace_update' ,
175
- 'Update a kv namespace in your Cloudflare account' ,
187
+ 'Update the title of a kv namespace in your Cloudflare account' ,
176
188
{
177
- namespace_id : kvNamespaceId ,
178
- title : kvNamespaceTitle ,
189
+ namespace_id : KvNamespaceIdSchema ,
190
+ title : KvNamespaceTitleSchema ,
179
191
} ,
180
192
async ( { namespace_id, title } ) => {
181
193
const account_id = agent . getActiveAccountId ( )
182
194
if ( ! account_id ) {
183
195
return MISSING_ACCOUNT_ID_RESPONSE
184
196
}
185
197
try {
186
- const namespaceUpdateResponse = await handleKVNamespaceUpdate ( {
187
- client : getCloudflareClient ( agent . props . accessToken ) ,
198
+ const client = getCloudflareClient ( agent . props . accessToken )
199
+ const result = await client . kv . namespaces . update ( namespace_id , {
188
200
account_id,
189
- namespace_id,
190
201
title,
191
202
} )
192
203
return {
193
204
content : [
194
205
{
195
206
type : 'text' ,
196
- text : JSON . stringify ( namespaceUpdateResponse ) ,
207
+ text : JSON . stringify ( result ?? { success : true } ) ,
197
208
} ,
198
209
] ,
199
210
}
@@ -202,7 +213,7 @@ export function registerKVTools(agent: CloudflareMcpAgent) {
202
213
content : [
203
214
{
204
215
type : 'text' ,
205
- text : `Error updating KV namespace: ${ error instanceof Error && error . message } ` ,
216
+ text : `Error updating KV namespace: ${ error instanceof Error ? error . message : String ( error ) } ` ,
206
217
} ,
207
218
] ,
208
219
}
0 commit comments