import { McpAgent } from "agents/mcp";
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
import { z } from "zod";
import { WOLService } from "./wol/wolService";
import {
SearchOptionsSchema,
DocumentRetrievalSchema,
PublicationBrowseSchema,
PUBLICATION_NAMES,
} from "./wol/types";
// Define our MCP agent with WOL tools
export class MyMCP extends McpAgent {
server = new McpServer({
name: "wol-mcp-server",
version: "1.0.0",
});
async init() {
// wol_search
this.server.tool(
"wol_search",
SearchOptionsSchema.shape, // accepts same fields as original schema
async (args: z.infer<typeof SearchOptionsSchema>) => {
const validated = SearchOptionsSchema.parse(args);
const { results, pagination } = await WOLService.search(
validated.query,
{
scope: validated.scope,
publications: validated.publications,
language: validated.language,
limit: validated.limit,
sort: validated.sort,
page: validated.page,
useOperators: validated.useOperators,
}
);
const keyPublications = results.filter(
(r) => r.resultType === "key_publication"
);
const documents = results.filter(
(r) => r.resultType === "document_result"
);
const header = `Search results for "${validated.query}" — page ${pagination.currentPage}/${pagination.totalPages} — total ${pagination.totalResults} results (page size ${pagination.pageSize}).`;
const keyPubSection =
`Key Publications (${keyPublications.length}):\n\n` +
(keyPublications.length > 0
? keyPublications
.map((result, i) => {
let output = `- ${i + 1}. ${result.title}\n`;
output += ` Publication: ${result.publication}\n`;
output += ` URL: ${result.url}\n`;
if (result.subheadings && result.subheadings.length > 0) {
output += ` Sections: ${result.subheadings.join("; ")}\n`;
}
return output;
})
.join("\n") + "\n"
: "(none)\n");
const docSection =
`Documents (showing up to ${validated.limit ?? 10}):\n\n` +
(documents.length > 0
? documents
.map((result, i) => {
let output =
`- ${i + 1}. ${result.title}` +
(result.occurrences
? ` — Occurrences: ${result.occurrences}`
: "") +
"\n";
output += ` Publication: ${result.publication}\n`;
output += ` URL: ${result.url}\n`;
if (
result.contextSnippets &&
result.contextSnippets.length > 0
) {
output += ` Preview: ${result.contextSnippets
.slice(0, 2)
.join(" | ")}\n`;
} else if ((result as any).snippet) {
output += ` Preview: ${(result as any).snippet}\n`;
}
return output;
})
.join("\n") + "\n"
: "(none)\n");
return {
content: [
{
type: "text",
text: `${header}\n\n${keyPubSection}\n${docSection}`,
},
],
};
}
);
// wol_get_document
this.server.tool(
"wol_get_document",
DocumentRetrievalSchema.shape,
async (args: z.infer<typeof DocumentRetrievalSchema>) => {
const validated = DocumentRetrievalSchema.parse(args);
const document = await WOLService.getDocumentByUrl(validated.url);
let formattedContent = `# ${document.title}\n\n`;
formattedContent += `Publication: ${document.publication}\n`;
formattedContent += `URL: ${document.url}\n`;
if (document.metadata) {
if (document.metadata.date)
formattedContent += `Date: ${document.metadata.date}\n`;
if ((document.metadata as any).volume)
formattedContent += `Volume: ${
(document.metadata as any).volume
}\n`;
if ((document.metadata as any).issue)
formattedContent += `Issue: ${(document.metadata as any).issue}\n`;
}
if (document.subheadings && document.subheadings.length > 0) {
formattedContent += `\nSubheadings (${document.subheadings.length}):\n`;
formattedContent +=
document.subheadings
.map((s) => `- ${s.title}\n ${s.url}`)
.join("\n") + "\n";
}
if (document.similarMaterials && document.similarMaterials.length > 0) {
formattedContent += `\nSimilar Material (${document.similarMaterials.length}):\n`;
formattedContent +=
document.similarMaterials
.map(
(s) =>
`- ${s.title}${s.subtitle ? ` — ${s.subtitle}` : ""}\n ${
s.url
}`
)
.join("\n") + "\n";
}
formattedContent += `\n\n${document.content}`;
return { content: [{ type: "text", text: formattedContent }] };
}
);
// wol_browse_publications
this.server.tool(
"wol_browse_publications",
PublicationBrowseSchema.shape,
async (args: z.infer<typeof PublicationBrowseSchema>) => {
const validated = PublicationBrowseSchema.parse(args);
const publications = await WOLService.browsePublications(
validated.type,
validated.language,
validated.year
);
const formatted = publications
.map(
(pub) =>
`**${pub.name}** (${pub.code})\n` +
`Description: ${pub.description}\n` +
`Language: ${pub.language}\n` +
(pub.years ? `Years: ${pub.years.join(", ")}\n` : "") +
`---\n`
)
.join("\n");
return {
content: [
{ type: "text", text: `Available Publications:\n\n${formatted}` },
],
};
}
);
}
}
export default {
fetch(request: Request, env: Env, ctx: ExecutionContext) {
const url = new URL(request.url);
if (url.pathname === "/sse" || url.pathname === "/sse/message") {
return MyMCP.serveSSE("/sse").fetch(request, env, ctx);
}
if (url.pathname === "/mcp") {
return MyMCP.serve("/mcp").fetch(request, env, ctx);
}
return new Response("Not found", { status: 404 });
},
};