@@ -41,9 +41,17 @@ public function args_to_schema( $args = [] ) {
4141 }
4242
4343 protected function sanitize_type ( $ type ) {
44+
45+ $ mapping = array (
46+ 'string ' => 'string ' ,
47+ 'integer ' => 'integer ' ,
48+ 'number ' => 'integer ' ,
49+ 'boolean ' => 'boolean ' ,
50+ );
51+
4452 // Validated types:
45- if ( $ type === ' string ' || $ type === ' integer ' || $ type === ' boolean ' ) {
46- return $ type ;
53+ if ( ! \is_array ( $ type) && isset ( $ mapping [ $ type ]) ) {
54+ return $ mapping [ $ type ] ;
4755 }
4856
4957 if ( $ type === 'array ' || $ type === 'object ' ) {
@@ -62,37 +70,38 @@ protected function sanitize_type( $type) {
6270 if ( \in_array ( 'string ' , $ type ) ) {
6371 return 'string ' ;
6472 }
65- if ( \in_array ( 'integer ' , $ type ) ) {
73+ if ( \in_array ( 'integer ' , $ type ) ) {
6674 return 'integer ' ;
6775 }
6876 // TODO, better types handling.
6977 return 'string ' ;
7078
7179 }
7280
81+ protected function is_route_allowed ( $ route ) {
82+ if (! \str_starts_with ($ route , '/wp/v2 ' )) {
83+ return false ; // Block all non wp/v2 routes for now.
84+ }
85+
86+ return ! in_array ( $ route , $ this ->rest_routes , true );
87+ }
88+
7389 public function map_rest_to_mcp ( Server $ mcp_server ) {
7490 $ server = rest_get_server ();
7591 $ routes = $ server ->get_routes ();
7692
77- foreach ( $ routes as $ route => $ endpoints ) {
93+ foreach ( $ routes as $ route => $ endpoints ) {
7894 foreach ( $ endpoints as $ endpoint ) {
79- // Only allowed routes
80- if ( ! isset ( $ this ->rest_routes [ $ route ] ) ) {
81- continue ;
95+ if ( ! $ this ->is_route_allowed ($ route ) ) {
96+ continue ; // This route is the block list.
8297 }
8398
84- // Generate a tool name off route e.g. /wp/v2/posts
85- $ tool_name = sanitize_key ($ route );
8699
87100 foreach ( $ endpoint ['methods ' ] as $ method_name => $ enabled ) {
88- // Only allowed methods
89- if ( ! isset ( $ this ->rest_routes [ $ route ][ $ method_name ] ) ) {
90- continue ;
91- }
92101
93102 $ tool = [
94- 'name ' => $ tool_name . ' _ ' . strtolower ( $ method_name ),
95- 'description ' => $ this ->rest_routes [ $ route ][ $ method_name ] ,
103+ 'name ' => $ this -> generate_tool_name ( $ route , $ method_name ),
104+ 'description ' => $ this ->generate_description ( $ route, $ method_name, $ endpoint ) ,
96105 'inputSchema ' => $ this ->args_to_schema ( $ endpoint ['args ' ] ),
97106 'callable ' => function ( $ inputs ) use ( $ route , $ method_name , $ server ){
98107 return $ this ->rest_callable ( $ inputs , $ route , $ method_name , $ server );
@@ -106,6 +115,53 @@ public function map_rest_to_mcp( Server $mcp_server ) {
106115 }
107116 }
108117
118+ protected function generate_tool_name ($ route , $ method_name ) {
119+ $ singular = '' ;
120+ if ( \str_contains ( $ route , '(?P< ' ) ) {
121+ $ singular = 'singular_ ' ;
122+ }
123+ return sanitize_title ($ route ) . '_ ' . $ singular . strtolower ( $ method_name );
124+ }
125+
126+ /**
127+ * Create desciptrion based on route and method.
128+ *
129+ *
130+ * Get a list of posts GET /wp/v2/posts
131+ * Get post with id GET /wp/v2/posts/(?P<id>[\d]+)
132+ */
133+ protected function generate_description ( $ route , $ method_name , $ endpoint ) {
134+
135+ // TODO all validation + exception handling.
136+ $ verb = array (
137+ 'GET ' => 'Get ' ,
138+ 'POST ' => 'Create ' ,
139+ 'PUT ' => 'Update ' ,
140+ 'PATCH ' => 'Update ' ,
141+ 'DELETE ' => 'Delete ' ,
142+ );
143+
144+ $ controller = $ endpoint ['callback ' ][0 ];
145+ if ( !isset ($ endpoint ['callback ' ]) || ! \is_object ($ endpoint ['callback ' ][0 ])) {
146+ throw new \Exception ('Not an object: ' . $ route );
147+ }
148+ if (! \method_exists ($ endpoint ['callback ' ][0 ], 'get_public_item_schema ' )) {
149+ throw new \Exception ('missing method: ' . $ route );
150+ }
151+
152+ $ schema = $ controller ->get_public_item_schema ();
153+ $ title = $ schema ['title ' ];
154+
155+ // is singular?
156+ $ singular = 'a ' ;
157+ if ( $ method_name === 'GET ' && ! \str_contains ( $ route , '(?P< ' )) {
158+ $ singular = 'List of ' ;
159+
160+ }
161+
162+ return $ verb [ $ method_name ] . ' ' . $ singular . ' ' . $ title ;
163+ }
164+
109165 protected function rest_callable ( $ inputs , $ route , $ method_name , $ server ) {
110166 preg_match_all ( '/\(?P<(\w+)>/ ' , $ route , $ matches );
111167
@@ -124,6 +180,9 @@ protected function rest_callable( $inputs, $route, $method_name, $server ) {
124180 $ request = new WP_REST_Request ( $ method_name , $ route );
125181 $ request ->set_body_params ( $ inputs );
126182
183+ /**
184+ * @var WP_REST_Response $response
185+ */
127186 $ response = $ server ->dispatch ( $ request );
128187
129188 return $ server ->response_to_data ( $ response , false );
0 commit comments