1515import { renderToolInterface } from "./toolDisplay.js" ;
1616import { escapeHtml } from "./sanitize.js" ;
1717
18- let toolDetailsAbortController = null ;
18+ let currentToolsList = [ ] ;
1919
2020/**
21- * Fetches a toolset from the /api/toolset endpoint and initiates creating the tool list.
21+ * Fetches a toolset from the /mcp endpoint and initiates creating the tool list.
2222 * @param {!HTMLElement } secondNavContent The HTML element where the tool list will be rendered.
2323 * @param {!HTMLElement } toolDisplayArea The HTML element where the details of a selected tool will be displayed.
2424 * @param {string } toolsetName The name of the toolset to load (empty string loads all tools).
@@ -27,10 +27,22 @@ let toolDetailsAbortController = null;
2727export async function loadTools ( secondNavContent , toolDisplayArea , toolsetName ) {
2828 secondNavContent . innerHTML = '<p>Fetching tools...</p>' ;
2929 try {
30- const response = await fetch ( `/api/toolset/${ toolsetName } ` ) ;
30+ const url = toolsetName ? `/mcp/${ toolsetName } ` : `/mcp` ;
31+ const response = await fetch ( url , {
32+ method : 'POST' ,
33+ headers : { 'Content-Type' : 'application/json' } ,
34+ body : JSON . stringify ( {
35+ jsonrpc : "2.0" ,
36+ id : "1" ,
37+ method : "tools/list" ,
38+ 'Mcp-Protocol-Version' : '2025-11-25'
39+ } )
40+ } ) ;
41+
3142 if ( ! response . ok ) {
3243 throw new Error ( `HTTP error! status: ${ response . status } ` ) ;
3344 }
45+
3446 const apiResponse = await response . json ( ) ;
3547 renderToolList ( apiResponse , secondNavContent , toolDisplayArea ) ;
3648 } catch ( error ) {
@@ -41,33 +53,32 @@ export async function loadTools(secondNavContent, toolDisplayArea, toolsetName)
4153
4254/**
4355 * Renders the list of tools as buttons within the provided HTML element.
44- * @param {?{tools: ? Object<string,*>} } apiResponse The API response object containing the tools.
56+ * @param {Object } apiResponse The API response object containing the tools.
4557 * @param {!HTMLElement } secondNavContent The HTML element to render the tool list into.
4658 * @param {!HTMLElement } toolDisplayArea The HTML element for displaying tool details (passed to event handlers).
4759 */
4860function renderToolList ( apiResponse , secondNavContent , toolDisplayArea ) {
4961 secondNavContent . innerHTML = '' ;
5062
51- if ( ! apiResponse || typeof apiResponse . tools !== 'object' || apiResponse . tools === null ) {
52- console . error ( 'Error: Expected an object with a " tools" property , but received:' , apiResponse ) ;
63+ if ( ! apiResponse || ! apiResponse . result || ! Array . isArray ( apiResponse . result . tools ) ) {
64+ console . error ( 'Error: Expected a valid MCP response with "result. tools" array , but received:' , apiResponse ) ;
5365 secondNavContent . textContent = 'Error: Invalid response format from toolset API.' ;
5466 return ;
5567 }
5668
57- const toolsObject = apiResponse . tools ;
58- const toolNames = Object . keys ( toolsObject ) ;
69+ currentToolsList = apiResponse . result . tools ;
5970
60- if ( toolNames . length === 0 ) {
71+ if ( currentToolsList . length === 0 ) {
6172 secondNavContent . textContent = 'No tools found.' ;
6273 return ;
6374 }
6475
6576 const ul = document . createElement ( 'ul' ) ;
66- toolNames . forEach ( toolName => {
77+ currentToolsList . forEach ( toolObj => {
6778 const li = document . createElement ( 'li' ) ;
6879 const button = document . createElement ( 'button' ) ;
69- button . textContent = toolName ;
70- button . dataset . toolname = toolName ;
80+ button . textContent = toolObj . name ;
81+ button . dataset . toolname = toolObj . name ;
7182 button . classList . add ( 'tool-button' ) ;
7283 button . addEventListener ( 'click' , ( event ) => handleToolClick ( event , secondNavContent , toolDisplayArea ) ) ;
7384 li . appendChild ( button ) ;
@@ -90,86 +101,81 @@ function handleToolClick(event, secondNavContent, toolDisplayArea) {
90101 currentActive . classList . remove ( 'active' ) ;
91102 }
92103 event . target . classList . add ( 'active' ) ;
93- fetchToolDetails ( toolName , toolDisplayArea ) ;
104+ renderToolDetails ( toolName , toolDisplayArea ) ;
94105 }
95106}
96107
97108/**
98- * Fetches details for a specific tool /api/tool endpoint.
99- * It aborts any previous in-flight request for tool details to stop race condition.
100- * @param {string } toolName The name of the tool to fetch details for.
109+ * Renders details for a specific tool from the cached MCP tools list.
110+ * @param {string } toolName The name of the tool to render details for.
101111 * @param {!HTMLElement } toolDisplayArea The HTML element to display the tool interface in.
102- * @returns {!Promise<void> } A promise that resolves when the tool details are fetched and rendered, or rejects on error.
103112 */
104- async function fetchToolDetails ( toolName , toolDisplayArea ) {
105- if ( toolDetailsAbortController ) {
106- toolDetailsAbortController . abort ( ) ;
107- console . debug ( "Aborted previous tool fetch." ) ;
108- }
113+ function renderToolDetails ( toolName , toolDisplayArea ) {
114+ const toolObject = currentToolsList . find ( t => t . name === toolName ) ;
109115
110- toolDetailsAbortController = new AbortController ( ) ;
111- const signal = toolDetailsAbortController . signal ;
116+ if ( ! toolObject ) {
117+ toolDisplayArea . innerHTML = `<p class="error">Tool "${ escapeHtml ( toolName ) } " data not found.</p>` ;
118+ return ;
119+ }
112120
113- toolDisplayArea . innerHTML = '<p>Loading tool details...</p>' ;
121+ console . debug ( "Rendering tool object: " , toolObject ) ;
114122
115- try {
116- const response = await fetch ( `/api/tool/${ encodeURIComponent ( toolName ) } ` , { signal } ) ;
117- if ( ! response . ok ) {
118- throw new Error ( `HTTP error! status: ${ response . status } ` ) ;
123+ let toolAuthRequired = [ ] ;
124+ let toolAuthParams = { } ;
125+ if ( toolObject . _meta ) {
126+ if ( toolObject . _meta [ "toolbox/authInvoke" ] ) {
127+ toolAuthRequired = toolObject . _meta [ "toolbox/authInvoke" ] ;
119128 }
120- const apiResponse = await response . json ( ) ;
121-
122- if ( ! apiResponse . tools || ! apiResponse . tools [ toolName ] ) {
123- throw new Error ( `Tool "${ toolName } " data not found in API response.` ) ;
129+ if ( toolObject . _meta [ "toolbox/authParam" ] ) {
130+ toolAuthParams = toolObject . _meta [ "toolbox/authParam" ] ;
124131 }
125- const toolObject = apiResponse . tools [ toolName ] ;
126- console . debug ( "Received tool object: " , toolObject )
127-
128- const toolInterfaceData = {
129- id : toolName ,
130- name : toolName ,
131- description : toolObject . description || "No description provided." ,
132- authRequired : toolObject . authRequired || [ ] ,
133- parameters : ( toolObject . parameters || [ ] ) . map ( param => {
134- let inputType = 'text' ;
135- const apiType = param . type ? param . type . toLowerCase ( ) : 'string' ;
136- let valueType = 'string' ;
137- let label = param . description || param . name ;
138-
139- if ( apiType === 'integer' || apiType === 'float' ) {
140- inputType = 'number' ;
141- valueType = 'number' ;
142- } else if ( apiType === 'boolean' ) {
143- inputType = 'checkbox' ;
144- valueType = 'boolean' ;
145- } else if ( apiType === 'array' ) {
146- inputType = 'textarea' ;
147- const itemType = param . items && param . items . type ? param . items . type . toLowerCase ( ) : 'string' ;
148- valueType = `array<${ itemType } >` ;
149- label += ' (Array)' ;
150- }
151-
152- return {
153- name : param . name ,
154- type : inputType ,
155- valueType : valueType ,
156- label : label ,
157- authServices : param . authServices , // TODO: to be updated when the native endpoint is no longer supported.
158- required : param . required || false ,
159- // defaultValue: param.default, can't do this yet bc tool manifest doesn't have default
160- } ;
161- } )
162- } ;
163-
164- console . debug ( "Transformed toolInterfaceData:" , toolInterfaceData ) ;
132+ }
165133
166- renderToolInterface ( toolInterfaceData , toolDisplayArea ) ;
167- } catch ( error ) {
168- if ( error . name === 'AbortError' ) {
169- console . debug ( "Previous fetch was aborted, expected behavior." ) ;
170- } else {
171- console . error ( `Failed to load details for tool "${ toolName } ":` , error ) ;
172- toolDisplayArea . innerHTML = `<p class="error">Failed to load details for ${ escapeHtml ( toolName ) } . ${ escapeHtml ( error . message ) } </p>` ;
173- }
134+ // Default processing if inputSchema properties are not present
135+ let toolParameters = [ ] ;
136+ if ( toolObject . inputSchema && toolObject . inputSchema . properties ) {
137+ const props = toolObject . inputSchema . properties ;
138+ const requiredFields = toolObject . inputSchema . required || [ ] ;
139+
140+ toolParameters = Object . keys ( props ) . map ( paramName => {
141+ const param = props [ paramName ] ;
142+ let inputType = 'text' ;
143+ const apiType = param . type ? param . type . toLowerCase ( ) : 'string' ;
144+ let valueType = 'string' ;
145+ let label = param . description || paramName ;
146+
147+ if ( apiType === 'integer' || apiType === 'number' ) {
148+ inputType = 'number' ;
149+ valueType = 'number' ;
150+ } else if ( apiType === 'boolean' ) {
151+ inputType = 'checkbox' ;
152+ valueType = 'boolean' ;
153+ } else if ( apiType === 'array' ) {
154+ inputType = 'textarea' ;
155+ const itemType = param . items && param . items . type ? param . items . type . toLowerCase ( ) : 'string' ;
156+ valueType = `array<${ itemType } >` ;
157+ label += ' (Array)' ;
158+ }
159+
160+ return {
161+ name : paramName ,
162+ type : inputType ,
163+ valueType : valueType ,
164+ label : label ,
165+ required : requiredFields . includes ( paramName ) ,
166+ authServices : toolAuthParams [ paramName ] || [ ]
167+ } ;
168+ } ) ;
174169 }
170+
171+ const toolInterfaceData = {
172+ id : toolName ,
173+ name : toolName ,
174+ description : toolObject . description || "No description provided." ,
175+ authRequired : toolAuthRequired ,
176+ parameters : toolParameters
177+ } ;
178+
179+ console . debug ( "Transformed toolInterfaceData:" , toolInterfaceData ) ;
180+ renderToolInterface ( toolInterfaceData , toolDisplayArea ) ;
175181}
0 commit comments