Skip to content

Commit 4098957

Browse files
committed
fix
1 parent 7fc5610 commit 4098957

1 file changed

Lines changed: 27 additions & 157 deletions

File tree

Lines changed: 27 additions & 157 deletions
Original file line numberDiff line numberDiff line change
@@ -1,168 +1,38 @@
1-
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
2-
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
3-
import { z } from "zod";
1+
import { Tables } from '../../utils/database.types';
42

5-
// Helper function to construct the full URL with properly replaced parameters
6-
const getFullUrlWithParams = (service: any, endpoint: any, params: any): string => {
7-
// Base API URL structure
8-
const baseApiUrl = "https://eu.api200.co/api";
3+
export const getFullUrlWithParams = (
4+
endpoint: Tables<'endpoints'>,
5+
endpointName: string,
6+
): string => {
7+
// Ensure endpointName starts with a forward slash
8+
const normalizedEndpointName = endpointName.startsWith('/') ? endpointName : `/${endpointName}`;
99

10-
// Get service name
11-
const serviceName = service.name;
12-
13-
// Start with endpoint name
14-
let endpointPath = endpoint.name;
15-
16-
// Replace path parameters in the URL
17-
if (endpoint.schema && endpoint.schema.parameters) {
18-
endpoint.schema.parameters.forEach((param: any) => {
19-
if (param.in === 'path' && params[param.name]) {
20-
// Replace {paramName} with actual value
21-
endpointPath = endpointPath.replace(`{${param.name}}`, params[param.name]);
22-
}
23-
});
10+
if (endpoint.regex_path === `^${endpoint.name}$`) {
11+
return endpoint.full_url;
2412
}
2513

26-
// Construct full URL
27-
const fullUrl = `${baseApiUrl}/${serviceName}${endpointPath}`;
14+
const regex = new RegExp(endpoint.regex_path!);
15+
const matches = normalizedEndpointName.match(regex);
2816

29-
// Add query parameters if any
30-
const queryParams: string[] = [];
31-
if (endpoint.schema && endpoint.schema.parameters) {
32-
endpoint.schema.parameters.forEach((param: any) => {
33-
if (param.in === 'query' && params[param.name] !== undefined) {
34-
queryParams.push(`${param.name}=${encodeURIComponent(params[param.name])}`);
35-
}
36-
});
17+
if (!matches) {
18+
//TODO return instead of throwing so it wont be catched in global error handler
19+
throw new Error(`API200 Error: Path parameters don't match provided`);
3720
}
3821

39-
// Append query string if query parameters exist
40-
return queryParams.length > 0 ? `${fullUrl}?${queryParams.join('&')}` : fullUrl;
41-
};
42-
43-
const main = async () => {
44-
const server = new McpServer({
45-
name: "API200 Client",
46-
version: "1.0.0"
47-
});
48-
49-
try {
50-
const userKey = "022fad02fed409a185c42c4416cea7c0";
51-
52-
const response = await fetch('http://localhost:8080/user/mcp-services', {
53-
headers: {
54-
"x-api-key": userKey
55-
}
56-
});
57-
const data = await response.json();
58-
59-
data.forEach((service: any) => {
60-
console.log(`Processing service: ${service.name}`);
61-
62-
service.endpoints.forEach((endpoint: any) => {
63-
console.log(`Processing endpoint: ${endpoint.name} (${endpoint.method})`);
64-
65-
// Create Zod schema dynamically based on endpoint parameters
66-
const paramSchema: Record<string, any> = {};
67-
68-
if (endpoint.schema && endpoint.schema.parameters) {
69-
endpoint.schema.parameters.forEach((param: any) => {
70-
// Determine the Zod type based on the parameter type
71-
let zodType;
72-
switch (param.type) {
73-
case 'integer':
74-
zodType = z.number().int();
75-
break;
76-
case 'number':
77-
zodType = z.number();
78-
break;
79-
case 'string':
80-
zodType = z.string();
81-
break;
82-
case 'boolean':
83-
zodType = z.boolean();
84-
break;
85-
default:
86-
zodType = z.string();
87-
}
22+
// Get the parameter names from the full_url
23+
const paramNames = endpoint.full_url.match(/\{([^}]+)\}/g) || [];
8824

89-
// Make it optional if not required
90-
if (!param.required) {
91-
zodType = zodType.optional();
92-
}
25+
// Start with the full URL
26+
let finalUrl = endpoint.full_url;
9327

94-
// Add description if available
95-
if (param.description) {
96-
zodType = zodType.describe(param.description);
97-
}
98-
99-
paramSchema[param.name] = zodType;
100-
});
101-
}
102-
103-
// Create a formatted toolName from the endpoint name
104-
// Remove leading slash and replace remaining slashes with underscores
105-
let toolName = endpoint.name.replace(/^\//, '').replace(/\//g, '_');
106-
// Replace curly braces notation with "by" prefix
107-
toolName = toolName.replace(/{([^}]+)}/g, 'by_$1');
108-
109-
// Register the tool with the server
110-
server.tool(
111-
toolName, // Tool name
112-
endpoint.description || `${endpoint.method} ${endpoint.name}`, // Description
113-
paramSchema, // Zod schema
114-
async (params) => {
115-
try {
116-
// Get the properly constructed URL, passing service object to the helper function
117-
const url = getFullUrlWithParams(service, endpoint, params);
118-
119-
console.log(`Making ${endpoint.method} request to: ${url}`);
120-
121-
// Make the actual API call
122-
const apiResponse = await fetch(url, {
123-
method: endpoint.method,
124-
headers: {
125-
"Accept": "application/json",
126-
"Content-Type": "application/json",
127-
"x-api-key": userKey
128-
}
129-
});
130-
131-
const data = await apiResponse.json();
132-
133-
// Return formatted response
134-
return {
135-
content: [
136-
{
137-
type: "text",
138-
text: JSON.stringify(data, null, 2)
139-
}
140-
]
141-
};
142-
} catch (error) {
143-
console.error(`Error calling ${endpoint.name}:`, error);
144-
return {
145-
content: [
146-
{
147-
type: "text",
148-
text: `Error: ${error instanceof Error ? error.message : String(error)}`
149-
}
150-
]
151-
};
152-
}
153-
}
154-
);
155-
156-
console.log(`Registered tool: ${toolName}`);
157-
});
158-
});
159-
} catch (error) {
160-
console.error("Error setting up MCP tools:", error);
161-
}
28+
// Replace each parameter with its corresponding value
29+
paramNames.forEach((param, index) => {
30+
// matches[0] is the full match, so we start from index 1 for capture groups
31+
const value = matches[index + 1];
32+
if (value) {
33+
finalUrl = finalUrl.replace(param, value);
34+
}
35+
});
16236

163-
// Start receiving messages on stdin and sending messages on stdout
164-
const transport = new StdioServerTransport();
165-
await server.connect(transport);
37+
return finalUrl;
16638
};
167-
168-
main();

0 commit comments

Comments
 (0)