mirror of
https://github.com/bendtherules/ask262.git
synced 2026-08-18 13:21:55 +00:00
feat(mcp-server): Add MCP server with tool registrations
Add MCP server implementation with support for: - ask262_search_spec_sections tool - ask262_get_section_content tool - ask262_evaluate_in_engine262 tool Includes proper error handling, input/output schemas, and structured content responses.
This commit is contained in:
@@ -0,0 +1,139 @@
|
||||
/**
|
||||
* Test script for Ask262 MCP Server
|
||||
* Tests all available tools
|
||||
*/
|
||||
|
||||
import { Client } from "@modelcontextprotocol/sdk/client/index.js";
|
||||
import { StdioClientTransport } from "@modelcontextprotocol/sdk/client/stdio.js";
|
||||
import type {
|
||||
EvaluateToolMCPOutput,
|
||||
GetSectionContentMCPOutput,
|
||||
SearchSpecMCPOutput,
|
||||
} from "../../mcp-server.js";
|
||||
|
||||
async function testMCPServer() {
|
||||
console.log("Starting MCP Server tests...\n");
|
||||
|
||||
// Create transport connecting to the server
|
||||
const transport = new StdioClientTransport({
|
||||
command: "bun",
|
||||
args: ["run", "src/mcp-server.ts"],
|
||||
});
|
||||
|
||||
// Create client
|
||||
const client = new Client(
|
||||
{
|
||||
name: "test-client",
|
||||
version: "1.0.0",
|
||||
},
|
||||
{
|
||||
capabilities: {},
|
||||
},
|
||||
);
|
||||
|
||||
try {
|
||||
// Connect to server
|
||||
await client.connect(transport);
|
||||
console.log("✓ Connected to MCP server\n");
|
||||
|
||||
// Test 1: List tools
|
||||
console.log("Test 1: Listing available tools...");
|
||||
const tools = await client.listTools();
|
||||
console.log(`Found ${tools.tools.length} tools:`);
|
||||
for (const tool of tools.tools) {
|
||||
const desc = tool.description ?? "No description";
|
||||
console.log(` - ${tool.name}: ${desc.substring(0, 60)}...`);
|
||||
}
|
||||
console.log("✓ Tools listed successfully\n");
|
||||
|
||||
// Test 2: Search spec sections
|
||||
console.log("Test 2: Testing ask262_search_spec_sections...");
|
||||
const searchResult = (await client.callTool({
|
||||
name: "ask262_search_spec_sections",
|
||||
arguments: {
|
||||
query: "array map method",
|
||||
},
|
||||
})) as SearchSpecMCPOutput;
|
||||
if (searchResult.isError) {
|
||||
throw new Error(`Search failed: ${searchResult.content[0]?.text}`);
|
||||
}
|
||||
const searchData = searchResult.structuredContent;
|
||||
console.log(`Found ${searchData.results?.length ?? 0} sections`);
|
||||
if (searchData.results && searchData.results.length > 0) {
|
||||
console.log(
|
||||
` First result: ${searchData.results[0].sectionId} - ${searchData.results[0].sectionTitle}`,
|
||||
);
|
||||
}
|
||||
console.log("✓ Search working (isError: false)\n");
|
||||
|
||||
// Test 3: Get section content
|
||||
console.log("Test 3: Testing ask262_get_section_content...");
|
||||
const contentResult = (await client.callTool({
|
||||
name: "ask262_get_section_content",
|
||||
arguments: {
|
||||
sectionId: "sec-array-prototype-map",
|
||||
recursive: false,
|
||||
},
|
||||
})) as GetSectionContentMCPOutput;
|
||||
if (contentResult.isError) {
|
||||
throw new Error(`Get section failed: ${contentResult.content[0]?.text}`);
|
||||
}
|
||||
const contentData = contentResult.structuredContent;
|
||||
console.log(
|
||||
`Content length: ${contentData.content?.length ?? 0} characters`,
|
||||
);
|
||||
console.log(`Sections visited: ${contentData.sectionCount ?? 0}`);
|
||||
console.log("✓ Section content retrieved (isError: false)\n");
|
||||
|
||||
// Test 4: Evaluate in engine262 - success case
|
||||
console.log("Test 4: Testing ask262_evaluate_in_engine262 (success)...");
|
||||
const evalResult = (await client.callTool({
|
||||
name: "ask262_evaluate_in_engine262",
|
||||
arguments: {
|
||||
code: "console.log('test'); let x = 1 + 2; console.log(x);",
|
||||
},
|
||||
})) as EvaluateToolMCPOutput;
|
||||
if (evalResult.isError) {
|
||||
throw new Error(`Evaluate failed: ${evalResult.content[0]?.text}`);
|
||||
}
|
||||
// Type guard: check for error in structuredContent
|
||||
const evalData = evalResult.structuredContent;
|
||||
if ("error" in evalData) {
|
||||
throw new Error(`Unexpected error: ${evalData.error}`);
|
||||
}
|
||||
console.log(
|
||||
`Important sections: ${evalData.importantSections?.length ?? 0}`,
|
||||
);
|
||||
console.log(`Other sections: ${evalData.otherSections?.length ?? 0}`);
|
||||
console.log(`Console output: ${JSON.stringify(evalData.consoleOutput)}`);
|
||||
console.log("✓ Code evaluation working (isError: false)\n");
|
||||
|
||||
// Test 5: Evaluate in engine262 - error case
|
||||
console.log("Test 5: Testing ask262_evaluate_in_engine262 (error)...");
|
||||
const evalErrorResult = (await client.callTool({
|
||||
name: "ask262_evaluate_in_engine262",
|
||||
arguments: {
|
||||
code: "invalid syntax here @#$%",
|
||||
},
|
||||
})) as EvaluateToolMCPOutput;
|
||||
if (!evalErrorResult.isError) {
|
||||
throw new Error("Expected error but got success");
|
||||
}
|
||||
// Verify error is in structuredContent
|
||||
const errorData = evalErrorResult.structuredContent;
|
||||
if (!("error" in errorData)) {
|
||||
throw new Error("Expected error in structuredContent");
|
||||
}
|
||||
console.log(`Got expected error: ${errorData.error}`);
|
||||
console.log("✓ Error handling working (isError: true)\n");
|
||||
|
||||
console.log("All tests passed! ✓");
|
||||
} catch (error) {
|
||||
console.error("Test failed:", error);
|
||||
process.exit(1);
|
||||
} finally {
|
||||
await client.close();
|
||||
}
|
||||
}
|
||||
|
||||
testMCPServer();
|
||||
Reference in New Issue
Block a user