1- import { DocsFetcher } from "../utils/docs-fetcher.js" ;
1+ import { Tool } from '@modelcontextprotocol/sdk/types.js' ;
2+ import axios from 'axios' ;
3+
4+ interface OpenAPISpec {
5+ openapi : string ;
6+ paths : Record < string , Record < string , any > > ;
7+ components ?: {
8+ schemas ?: Record < string , any > ;
9+ } ;
10+ }
11+
12+ interface APIEndpoint {
13+ path : string ;
14+ method : string ;
15+ operationId ?: string ;
16+ summary ?: string ;
17+ description ?: string ;
18+ parameters ?: any [ ] ;
19+ requestBody ?: any ;
20+ responses ?: Record < string , any > ;
21+ tags ?: string [ ] ;
22+ }
23+
24+ export const apiReferenceTool : Tool = {
25+ name : 'get_api_reference' ,
26+ description : 'Get detailed API reference information for Vapi endpoints using the actual OpenAPI specification' ,
27+ inputSchema : {
28+ type : 'object' ,
29+ properties : {
30+ endpoint : {
31+ type : 'string' ,
32+ description : 'API endpoint or resource to get reference for (e.g., "assistants", "calls", "phone-numbers")'
33+ } ,
34+ method : {
35+ type : 'string' ,
36+ enum : [ 'GET' , 'POST' , 'PUT' , 'DELETE' , 'PATCH' , 'all' ] ,
37+ default : 'all' ,
38+ description : 'HTTP method (optional)'
39+ } ,
40+ includeExamples : {
41+ type : 'boolean' ,
42+ default : true ,
43+ description : 'Include request/response examples'
44+ }
45+ } ,
46+ required : [ 'endpoint' ]
47+ }
48+ } ;
249
3- const docsFetcher = new DocsFetcher ( ) ;
50+ export async function handleApiReference ( args : any ) : Promise < string > {
51+ const { endpoint, method = 'all' , includeExamples = true } = args ;
452
5- /**
6- * Get detailed API reference information for Vapi endpoints
7- */
8- export async function getApiReference (
9- endpoint : string ,
10- method : string = "all" ,
11- includeExamples : boolean = true
12- ) : Promise < string > {
1353 try {
14- // Get all API reference pages
15- const allApiPages = await docsFetcher . getApiReference ( ) ;
54+ // Fetch the OpenAPI spec
55+ const response = await axios . get ( 'https://api.vapi.ai/api-json' ) ;
56+ const spec : OpenAPISpec = response . data ;
1657
17- // Search for endpoint in API pages
18- const searchTerm = endpoint . toLowerCase ( ) ;
19- let relevantApiPages = allApiPages . filter ( page =>
20- page . title . toLowerCase ( ) . includes ( searchTerm ) ||
21- page . section . toLowerCase ( ) . includes ( searchTerm ) ||
22- page . url . toLowerCase ( ) . includes ( searchTerm ) ||
23- page . url . toLowerCase ( ) . includes ( endpoint . toLowerCase ( ) )
24- ) ;
25-
26- // If no direct matches, try broader search
27- if ( relevantApiPages . length === 0 ) {
28- const broadSearchResults = await docsFetcher . searchDocumentation ( endpoint + " api" ) ;
29- relevantApiPages = broadSearchResults . results . slice ( 0 , 3 ) ;
58+ // Find matching endpoints
59+ const matchingEndpoints = findMatchingEndpoints ( spec , endpoint , method ) ;
60+
61+ if ( matchingEndpoints . length === 0 ) {
62+ return generateNoResultsResponse ( endpoint , method ) ;
3063 }
3164
32- if ( relevantApiPages . length === 0 ) {
33- return `# π§ No API Reference Found
34-
35- No API reference found for "${ endpoint } ".
36-
37- ## π Available API Endpoints:
38-
39- ${ allApiPages . slice ( 0 , 8 ) . map ( page => `- **${ page . title } ** - ${ page . section } ` ) . join ( '\n' ) }
40-
41- ## π― Popular API Endpoints:
42-
43- - **Assistants** - Create and manage voice assistants
44- - **Calls** - Make and manage phone calls
45- - **Phone Numbers** - Manage phone numbers
46- - **Tools** - Define custom functions
47- - **Webhooks** - Configure event notifications
48- - **Analytics** - Call analytics and insights
49- - **Files** - File upload and management
50- - **Squads** - Team management
51-
52- ## π‘ Tips:
53- - Try searching for broader terms (e.g., "assistant" instead of "assistants")
54- - Use the \`search_documentation\` tool for more general searches
55- - Check the full API reference at https://docs.vapi.ai/api-reference
56-
57- Try searching for one of the popular endpoints above!` ;
65+ // Generate comprehensive API reference
66+ return generateApiReference ( matchingEndpoints , spec , includeExamples ) ;
67+
68+ } catch ( error ) {
69+ console . error ( 'Failed to fetch OpenAPI spec:' , error ) ;
70+ return generateErrorResponse ( endpoint ) ;
71+ }
72+ }
73+
74+ function findMatchingEndpoints ( spec : OpenAPISpec , endpoint : string , method : string ) : APIEndpoint [ ] {
75+ const endpoints : APIEndpoint [ ] = [ ] ;
76+ const searchTerm = endpoint . toLowerCase ( ) ;
77+
78+ for ( const [ path , pathMethods ] of Object . entries ( spec . paths ) ) {
79+ for ( const [ httpMethod , operation ] of Object . entries ( pathMethods ) ) {
80+ // Skip if method filter doesn't match
81+ if ( method !== 'all' && httpMethod . toUpperCase ( ) !== method . toUpperCase ( ) ) {
82+ continue ;
83+ }
84+
85+ // Check if endpoint matches path, operationId, summary, or tags
86+ const pathMatch = path . toLowerCase ( ) . includes ( searchTerm ) ;
87+ const operationMatch = operation . operationId ?. toLowerCase ( ) . includes ( searchTerm ) ;
88+ const summaryMatch = operation . summary ?. toLowerCase ( ) . includes ( searchTerm ) ;
89+ const tagMatch = operation . tags ?. some ( ( tag : string ) =>
90+ tag . toLowerCase ( ) . includes ( searchTerm )
91+ ) ;
92+
93+ if ( pathMatch || operationMatch || summaryMatch || tagMatch ) {
94+ endpoints . push ( {
95+ path,
96+ method : httpMethod . toUpperCase ( ) ,
97+ operationId : operation . operationId ,
98+ summary : operation . summary ,
99+ description : operation . description ,
100+ parameters : operation . parameters ,
101+ requestBody : operation . requestBody ,
102+ responses : operation . responses ,
103+ tags : operation . tags
104+ } ) ;
105+ }
58106 }
59-
60- let response = `# π§ API Reference for "${ endpoint } "\n\n` ;
61- response += `Found ${ relevantApiPages . length } API reference(s) for "${ endpoint } "\n` ;
62- if ( method !== "all" ) {
63- response += `**Method:** ${ method . toUpperCase ( ) } \n` ;
107+ }
108+
109+ return endpoints ;
110+ }
111+
112+ function generateApiReference ( endpoints : APIEndpoint [ ] , spec : OpenAPISpec , includeExamples : boolean ) : string {
113+ let result = `# π§ API Reference for "${ endpoints [ 0 ] ?. path . split ( '/' ) [ 1 ] || 'endpoint' } "\n\n` ;
114+
115+ result += `Found ${ endpoints . length } endpoint(s)\n\n` ;
116+
117+ endpoints . forEach ( ( endpoint , index ) => {
118+ result += `## π ${ index + 1 } . ${ endpoint . method } ${ endpoint . path } \n\n` ;
119+
120+ if ( endpoint . summary ) {
121+ result += `**Summary:** ${ endpoint . summary } \n\n` ;
64122 }
65- response += `**Include Examples:** ${ includeExamples ? 'Yes' : 'No' } \n\n` ;
66-
67- // Fetch and return actual content for each API reference
68- for ( let i = 0 ; i < Math . min ( relevantApiPages . length , 3 ) ; i ++ ) {
69- const apiPage = relevantApiPages [ i ] ;
70- if ( ! apiPage ) continue ;
123+
124+ if ( endpoint . description ) {
125+ result += `**Description:** ${ endpoint . description } \n\n` ;
126+ }
127+
128+ if ( endpoint . operationId ) {
129+ result += `**Operation ID:** \`${ endpoint . operationId } \`\n\n` ;
130+ }
131+
132+ if ( endpoint . tags && endpoint . tags . length > 0 ) {
133+ result += `**Tags:** ${ endpoint . tags . join ( ', ' ) } \n\n` ;
134+ }
135+
136+ // Parameters
137+ if ( endpoint . parameters && endpoint . parameters . length > 0 ) {
138+ result += `### Parameters\n\n` ;
139+ endpoint . parameters . forEach ( ( param : any ) => {
140+ result += `- **${ param . name } ** (${ param . in } )` ;
141+ if ( param . required ) result += ` *required*` ;
142+ result += `\n` ;
143+ if ( param . description ) result += ` - ${ param . description } \n` ;
144+ if ( param . schema ?. type ) result += ` - Type: \`${ param . schema . type } \`\n` ;
145+ if ( param . schema ?. enum ) result += ` - Allowed values: \`${ param . schema . enum . join ( '`, `' ) } \`\n` ;
146+ result += `\n` ;
147+ } ) ;
148+ }
149+
150+ // Request Body
151+ if ( endpoint . requestBody ) {
152+ result += `### Request Body\n\n` ;
153+ if ( endpoint . requestBody . description ) {
154+ result += `${ endpoint . requestBody . description } \n\n` ;
155+ }
71156
72- try {
73- const content = await docsFetcher . fetchPageContent ( apiPage ) ;
157+ if ( endpoint . requestBody . content ) {
158+ const contentTypes = Object . keys ( endpoint . requestBody . content ) ;
159+ result += `**Content Types:** ${ contentTypes . join ( ', ' ) } \n\n` ;
74160
75- response += `## π ${ i + 1 } . ${ apiPage . title } \n\n` ;
76- response += `**Section:** ${ apiPage . section } \n` ;
77- response += `**Category:** ${ apiPage . category } \n` ;
78- response += `**URL:** ${ apiPage . url } \n\n` ;
79-
80- // Add the actual content
81- response += `### Content:\n\n${ content } \n\n` ;
82- response += `---\n\n` ;
83-
84- } catch ( error ) {
85- response += `## π ${ i + 1 } . ${ apiPage . title } \n\n` ;
86- response += `**Section:** ${ apiPage . section } \n` ;
87- response += `**URL:** ${ apiPage . url } \n\n` ;
88- response += `β οΈ Content temporarily unavailable. Please visit the URL above.\n\n` ;
89- response += `---\n\n` ;
161+ // Show schema for application/json if available
162+ const jsonContent = endpoint . requestBody . content [ 'application/json' ] ;
163+ if ( jsonContent ?. schema && includeExamples ) {
164+ result += `**Schema:**\n\`\`\`json\n${ JSON . stringify ( jsonContent . schema , null , 2 ) } \`\`\`\n\n` ;
165+ }
90166 }
91167 }
92-
93- response += `## π― Next Steps\n\n` ;
94- response += `After reviewing this API reference:\n` ;
95- response += `- Use \`get_examples\` to see code implementations\n` ;
96- response += `- Use \`get_guides\` for step-by-step tutorials\n` ;
97- response += `- Visit the URLs above for interactive API testing\n` ;
98- response += `- Check the **Quickstart** guides for basic setup\n\n` ;
99168
100- response += `## π Additional Resources\n\n` ;
101- response += `- **Full API Reference:** https://docs.vapi.ai/api-reference\n` ;
102- response += `- **Interactive API:** https://api.vapi.ai/api\n` ;
103- response += `- **OpenAPI Spec:** https://api.vapi.ai/api-json\n` ;
104- response += `- **Dashboard:** https://dashboard.vapi.ai\n` ;
105- response += `- **Discord Community:** https://discord.gg/vapi` ;
106-
107- return response ;
169+ // Responses
170+ if ( endpoint . responses ) {
171+ result += `### Responses\n\n` ;
172+ Object . entries ( endpoint . responses ) . forEach ( ( [ statusCode , response ] : [ string , any ] ) => {
173+ result += `**${ statusCode } ** - ${ response . description || 'Success' } \n` ;
174+
175+ if ( response . content && includeExamples ) {
176+ const contentTypes = Object . keys ( response . content ) ;
177+ if ( contentTypes . length > 0 ) {
178+ result += ` - Content Types: ${ contentTypes . join ( ', ' ) } \n` ;
179+ }
180+ }
181+ result += `\n` ;
182+ } ) ;
183+ }
108184
109- } catch ( error ) {
110- const errorMessage = error instanceof Error ? error . message : "Unknown error" ;
111- return `# β API Reference Error
112-
113- Failed to fetch API reference: ${ errorMessage }
114-
115- ## π οΈ Troubleshooting:
116- - The documentation server might be temporarily unavailable
117- - Try again in a few moments
118- - Check your internet connection
119-
120- ## π Manual Resources:
121- - **Full API Reference:** https://docs.vapi.ai/api-reference
122- - **Interactive API:** https://api.vapi.ai/api
123- - **OpenAPI Spec:** https://api.vapi.ai/api-json
124- - **Postman Collection:** Available in the dashboard
125-
126- ## π― Popular API Endpoints:
127- - **Assistants:** https://docs.vapi.ai/api-reference/assistants
128- - **Calls:** https://docs.vapi.ai/api-reference/calls
129- - **Phone Numbers:** https://docs.vapi.ai/api-reference/phone-numbers
130- - **Tools:** https://docs.vapi.ai/api-reference/tools` ;
131- }
185+ // Add link to interactive API
186+ result += `### π Try it out\n\n` ;
187+ result += `**Interactive API:** https://api.vapi.ai/api#${ endpoint . operationId || endpoint . method . toLowerCase ( ) + endpoint . path . replace ( / [ { } ] / g, '' ) } \n\n` ;
188+
189+ if ( index < endpoints . length - 1 ) {
190+ result += `---\n\n` ;
191+ }
192+ } ) ;
193+
194+ // Footer with additional resources
195+ result += `## π― Additional Resources\n\n` ;
196+ result += `- **Full API Reference:** https://docs.vapi.ai/api-reference\n` ;
197+ result += `- **Interactive API Explorer:** https://api.vapi.ai/api\n` ;
198+ result += `- **OpenAPI Spec:** https://api.vapi.ai/api-json\n` ;
199+ result += `- **Dashboard:** https://dashboard.vapi.ai\n` ;
200+ result += `- **Discord Community:** https://discord.gg/vapi\n\n` ;
201+
202+ result += `π‘ **Pro Tip:** Use the interactive API explorer to test endpoints with your actual API key and see real request/response examples.\n` ;
203+
204+ return result ;
205+ }
206+
207+ function generateNoResultsResponse ( endpoint : string , method : string ) : string {
208+ return `# π No API Reference Found\n\n` +
209+ `No API endpoints found for "${ endpoint } " with method "${ method } ".\n\n` +
210+ `## π‘ Suggestions:\n` +
211+ `- Try broader search terms (e.g., "call" instead of "voice-call")\n` +
212+ `- Use "all" for method to see all HTTP methods\n` +
213+ `- Check for typos in your search query\n` +
214+ `- Try these common endpoints: assistants, calls, phone-numbers, tools, webhooks\n\n` +
215+ `## π Available Resources:\n` +
216+ `- **Full API Reference:** https://docs.vapi.ai/api-reference\n` +
217+ `- **Interactive API:** https://api.vapi.ai/api\n` +
218+ `- **OpenAPI Spec:** https://api.vapi.ai/api-json\n` ;
219+ }
220+
221+ function generateErrorResponse ( endpoint : string ) : string {
222+ return `# β API Reference Error\n\n` +
223+ `Sorry, there was an error fetching the API reference for "${ endpoint } ".\n\n` +
224+ `## π Alternative Resources:\n` +
225+ `- **Full API Reference:** https://docs.vapi.ai/api-reference\n` +
226+ `- **Interactive API:** https://api.vapi.ai/api\n` +
227+ `- **OpenAPI Spec:** https://api.vapi.ai/api-json\n` +
228+ `- **Dashboard:** https://dashboard.vapi.ai\n\n` +
229+ `Please try again later or visit the links above for complete API documentation.` ;
132230}
0 commit comments