2import { Hono, Context } from 'npm:hono';
3import { SSETransport } from 'npm:hono-mcp-server-sse-transport';
4import { toFetchResponse, toReqRes } from "npm:fetch-to-node";
5import { z } from "npm:zod";
6import lunr from "https://cdn.skypack.dev/lunr";
181 { limit: z.number().optional() },
182 async ({ limit }) => {
183 console.log(`${new Date().toISOString()} Fetching proverbs data`);
184 const proverbs = await fetch("https://www.joshbeckman.org/assets/js/proverbs.json").then((res) => res.json());
185 const results = proverbs
186 .sort(() => Math.random() - 0.5)
187 .slice(0, limit || 100);
188 console.log(`${new Date().toISOString()} Proverbs data fetched`);
189 const data = results.join("\n");
190 return {
198 { limit: z.number().optional(), tag: z.string() },
199 async ({ limit, tag }) => {
200 console.log(`${new Date().toISOString()} Fetching sequences data for tag: ${tag}`);
201 const sequences = await fetch("https://www.joshbeckman.org/assets/js/sequences.json").then((res) => res.json());
202 const results = sequences
203 .filter((seq: any) => seq.topic == tag)
204 .slice(0, limit || 100);
205 console.log(`${new Date().toISOString()} Sequences data fetched`);
206 if (results.length == 0) {
207 return {
222 { id: z.string() },
223 async ({ id }) => {
224 console.log(`${new Date().toISOString()} Fetching sequence data for ID: ${id}`);
225 const sequences = await fetch("https://www.joshbeckman.org/assets/js/sequences.json").then((res) => res.json());
226 const sequence = sequences.find((seq: any) => seq.id == id);
227 console.log(`${new Date().toISOString()} Sequence data fetched`);
228 if (!sequence) {
229 return {
242 { query: z.string(), limit: z.number().optional() },
243 async ({ query, limit }) => {
244 console.log(`${new Date().toISOString()} Fetching tags data for search`);
245 const tags = await fetch("https://www.joshbeckman.org/assets/js/tags.json").then((res) => res.json());
246 const tagsIndex = buildTagsIndex(tags);
247 console.log(`${new Date().toISOString()} Tags search index built`);
268 { tags: z.array(z.string()) },
269 async () => {
270 console.log(`${new Date().toISOString()} Fetching tags data`);
271 const sourceTags = await fetch("https://www.joshbeckman.org/assets/js/tags.json")
272 .then((res) => res.json());
273 console.log(`${new Date().toISOString()} Tags data fetched`);
274 const data = sourceTags.filter((tag) => tags.includes(tag.name)).map((tag) => {
275 return `[${tag.name}](${SITE_URL}${tag.url})`;
285 {},
286 async () => {
287 console.log(`${new Date().toISOString()} Fetching tags data`);
288 const tags = await fetch("https://www.joshbeckman.org/assets/js/tags.json")
289 .then((res) => res.json());
290 const data = tags.sort((a, b) => a.name.localeCompare(b.name)).map((tag) => {
291 return tag.name;
292 }).join("\n");
293 console.log(`${new Date().toISOString()} Tags data fetched`);
294 return {
295 content: [{ type: "text", text: data }]
299 server.tool(
300 "get_post",
301 "Get the full content and metadata of a specific post by its URL. This tool fetches the post data from the site and returns it in a structured format, including title, content, date, tags, author, and more.",
302 { url: z.string() },
303 async ({ url }) => {
304 console.log(`${new Date().toISOString()} Fetching post data for URL: ${url}`);
305 const searchData = await fetch("https://www.joshbeckman.org/assets/js/SearchData.json").then((res) => res.json());
306 const db: Array<Post> = Object.values(searchData).filter(postFilter).map((post) => {
307 post.author_id = post.author_id || "joshbeckman";
310 });
311 const post = db.find((post) => post.url == url || `${SITE_URL}${post.url}` == url);
312 console.log(`${new Date().toISOString()} Post data fetched`);
313 if (!post) {
314 return {
337 console.log(`${new Date().toISOString()} loading search data`);
338 const [searchData, indexCache] = await Promise.all([
339 fetch("https://www.joshbeckman.org/assets/js/SearchData.json").then((res) => res.json()),
340 fetch("https://www.joshbeckman.org/assets/js/lunr-index.json").then((res) => res.json()),
341 ]);
342 console.log(`${new Date().toISOString()} search data loaded`);
450 });
451
452 return toFetchResponse(res);
453 } catch (e) {
454 console.error(e);
501 * This will be exposed as a Val.town HTTP endpoint
502 */
503export default app.fetch;
504