mirror of
https://github.com/ArthurDanjou/artapi.git
synced 2026-01-14 21:59:25 +01:00
Refactor MCP API: Remove deprecated endpoints and add new resource handlers
- Deleted old API endpoints for contact, education, experiences, hobbies, languages, profile, projects, skills, and uses. - Introduced new resource handlers for contact, education, experiences, hobbies, languages, profile, projects, skills, and uses with structured responses. - Added new MCP prompts for real-time activity, contact information, hobbies, languages, profile, projects, skills, stats, and status page. - Implemented tools for fetching real-time activity, resume links, coding stats, and weather information. - Removed legacy MCP server route and replaced it with a modular approach for better maintainability.
This commit is contained in:
14
server/mcp/prompts/activity.ts
Normal file
14
server/mcp/prompts/activity.ts
Normal file
@@ -0,0 +1,14 @@
|
||||
export default defineMcpPrompt({
|
||||
description: 'Generates a prompt to retrieve Arthur Danjou\'s current real-time activity status, including what he is currently working on.',
|
||||
handler: async () => {
|
||||
return {
|
||||
messages: [{
|
||||
role: 'user',
|
||||
content: {
|
||||
type: 'text',
|
||||
text: `Provide me the realtime activity of Arthur Danjou.`
|
||||
}
|
||||
}]
|
||||
}
|
||||
}
|
||||
})
|
||||
14
server/mcp/prompts/contact.ts
Normal file
14
server/mcp/prompts/contact.ts
Normal file
@@ -0,0 +1,14 @@
|
||||
export default defineMcpPrompt({
|
||||
description: 'Generates a prompt to retrieve Arthur Danjou\'s contact information and social media links, including email, LinkedIn, GitHub, Twitter, Discord, and personal websites.',
|
||||
handler: async () => {
|
||||
return {
|
||||
messages: [{
|
||||
role: 'user',
|
||||
content: {
|
||||
type: 'text',
|
||||
text: `How can I contact Arthur Danjou? Provide all contact methods and social links.`
|
||||
}
|
||||
}]
|
||||
}
|
||||
}
|
||||
})
|
||||
14
server/mcp/prompts/hobbies.ts
Normal file
14
server/mcp/prompts/hobbies.ts
Normal file
@@ -0,0 +1,14 @@
|
||||
export default defineMcpPrompt({
|
||||
description: 'Generates a prompt to retrieve information about Arthur Danjou\'s personal hobbies, interests, and passions outside of professional work.',
|
||||
handler: async () => {
|
||||
return {
|
||||
messages: [{
|
||||
role: 'user',
|
||||
content: {
|
||||
type: 'text',
|
||||
text: `What are the hobbies, interests and passions of Arthur Danjou?`
|
||||
}
|
||||
}]
|
||||
}
|
||||
}
|
||||
})
|
||||
14
server/mcp/prompts/languages.ts
Normal file
14
server/mcp/prompts/languages.ts
Normal file
@@ -0,0 +1,14 @@
|
||||
export default defineMcpPrompt({
|
||||
description: 'Generates a prompt to retrieve the languages spoken by Arthur Danjou along with detailed proficiency levels for each language.',
|
||||
handler: async () => {
|
||||
return {
|
||||
messages: [{
|
||||
role: 'user',
|
||||
content: {
|
||||
type: 'text',
|
||||
text: `What languages does Arthur Danjou speak and at what proficiency level?`
|
||||
}
|
||||
}]
|
||||
}
|
||||
}
|
||||
})
|
||||
14
server/mcp/prompts/profile.ts
Normal file
14
server/mcp/prompts/profile.ts
Normal file
@@ -0,0 +1,14 @@
|
||||
export default defineMcpPrompt({
|
||||
description: 'Generates a prompt to retrieve comprehensive professional profile information about Arthur Danjou, including biography, location, availability status, career goals, and work preferences.',
|
||||
handler: async () => {
|
||||
return {
|
||||
messages: [{
|
||||
role: 'user',
|
||||
content: {
|
||||
type: 'text',
|
||||
text: `Provide me comprehensive profile information about Arthur Danjou including his bio, location, availability, career goals, and work preferences.`
|
||||
}
|
||||
}]
|
||||
}
|
||||
}
|
||||
})
|
||||
14
server/mcp/prompts/projects.ts
Normal file
14
server/mcp/prompts/projects.ts
Normal file
@@ -0,0 +1,14 @@
|
||||
export default defineMcpPrompt({
|
||||
description: 'Generates a prompt to retrieve a comprehensive list of personal and professional projects developed by Arthur Danjou, showcasing his technical skills and achievements.',
|
||||
handler: async () => {
|
||||
return {
|
||||
messages: [{
|
||||
role: 'user',
|
||||
content: {
|
||||
type: 'text',
|
||||
text: `Provide me a list of projects done by Arthur Danjou.`
|
||||
}
|
||||
}]
|
||||
}
|
||||
}
|
||||
})
|
||||
19
server/mcp/prompts/resume.ts
Normal file
19
server/mcp/prompts/resume.ts
Normal file
@@ -0,0 +1,19 @@
|
||||
import z from 'zod'
|
||||
|
||||
export default defineMcpPrompt({
|
||||
description: 'Generates a prompt to request and retrieve Arthur Danjou\'s professional resume in the specified language (English or French).',
|
||||
inputSchema: {
|
||||
lang: z.enum(['en', 'fr']).describe('The language for the resume: \'en\' for English or \'fr\' for French.')
|
||||
},
|
||||
handler: async ({ lang }) => {
|
||||
return {
|
||||
messages: [{
|
||||
role: 'user',
|
||||
content: {
|
||||
type: 'text',
|
||||
text: `Provide me the link to download Arthur Danjou's resume in ${lang === 'en' ? 'English' : 'French'}.`
|
||||
}
|
||||
}]
|
||||
}
|
||||
}
|
||||
})
|
||||
14
server/mcp/prompts/skills.ts
Normal file
14
server/mcp/prompts/skills.ts
Normal file
@@ -0,0 +1,14 @@
|
||||
export default defineMcpPrompt({
|
||||
description: 'Generates a prompt to retrieve a comprehensive list of technical skills, programming languages, frameworks, and tools mastered by Arthur Danjou.',
|
||||
handler: async () => {
|
||||
return {
|
||||
messages: [{
|
||||
role: 'user',
|
||||
content: {
|
||||
type: 'text',
|
||||
text: `Provide me a list of skills that Arthur Danjou masters.`
|
||||
}
|
||||
}]
|
||||
}
|
||||
}
|
||||
})
|
||||
14
server/mcp/prompts/stats.ts
Normal file
14
server/mcp/prompts/stats.ts
Normal file
@@ -0,0 +1,14 @@
|
||||
export default defineMcpPrompt({
|
||||
description: 'Generates a prompt to retrieve Arthur Danjou\'s detailed coding statistics and analytics powered by WakaTime, including programming languages, time spent coding, and productivity metrics.',
|
||||
handler: async () => {
|
||||
return {
|
||||
messages: [{
|
||||
role: 'user',
|
||||
content: {
|
||||
type: 'text',
|
||||
text: `Provide me the stats of Arthur Danjou powered by Wakatime.`
|
||||
}
|
||||
}]
|
||||
}
|
||||
}
|
||||
})
|
||||
14
server/mcp/prompts/status-page.ts
Normal file
14
server/mcp/prompts/status-page.ts
Normal file
@@ -0,0 +1,14 @@
|
||||
export default defineMcpPrompt({
|
||||
description: 'Generates a prompt to retrieve the real-time status page of Arthur Danjou\'s homelab infrastructure, including uptime monitoring and incident reports powered by UptimeKuma.',
|
||||
handler: async () => {
|
||||
return {
|
||||
messages: [{
|
||||
role: 'user',
|
||||
content: {
|
||||
type: 'text',
|
||||
text: `Provide me the status page activity of Arthur Danjou's homelab, including uptime and incidents.`
|
||||
}
|
||||
}]
|
||||
}
|
||||
}
|
||||
})
|
||||
20
server/mcp/prompts/uses-by-category.ts
Normal file
20
server/mcp/prompts/uses-by-category.ts
Normal file
@@ -0,0 +1,20 @@
|
||||
import z from 'zod'
|
||||
|
||||
export default defineMcpPrompt({
|
||||
description: 'Generates a prompt to retrieve tools, software, and hardware used by Arthur Danjou, filtered by a specific category (homelab, IDE, hardware, or software).',
|
||||
inputSchema: {
|
||||
categoryName: z.enum(['homelab', 'ide', 'hardware', 'software']).describe('The category to filter by: \'homelab\', \'ide\', \'hardware\', or \'software\'.')
|
||||
},
|
||||
handler: async ({ categoryName }) => {
|
||||
return {
|
||||
messages: [
|
||||
{
|
||||
role: 'user',
|
||||
content: {
|
||||
type: 'text',
|
||||
text: `How can I view the setup of Arthur for this category : ${categoryName}?`
|
||||
}
|
||||
}
|
||||
] }
|
||||
}
|
||||
})
|
||||
21
server/mcp/resources/contact.ts
Normal file
21
server/mcp/resources/contact.ts
Normal file
@@ -0,0 +1,21 @@
|
||||
export default defineMcpResource({
|
||||
title: 'Arthur Danjou - Contact Information & Social Media Links',
|
||||
description: 'Contact information and social media links for Arthur Danjou, including email, LinkedIn, GitHub, Twitter, Discord, and personal websites',
|
||||
uri: 'resource://artmcp/contact',
|
||||
cache: '1 hour',
|
||||
handler: async (uri: URL) => {
|
||||
const event = useEvent()
|
||||
|
||||
const result = await queryCollection(event, 'contact')
|
||||
.where('extension', '=', 'json')
|
||||
.first()
|
||||
|
||||
return {
|
||||
contents: [{
|
||||
uri: uri.toString(),
|
||||
mimeType: 'text/json',
|
||||
text: JSON.stringify(result.body, null, 2)
|
||||
}]
|
||||
}
|
||||
}
|
||||
})
|
||||
29
server/mcp/resources/education.ts
Normal file
29
server/mcp/resources/education.ts
Normal file
@@ -0,0 +1,29 @@
|
||||
export default defineMcpResource({
|
||||
title: 'Arthur Danjou - Education & Academic Background',
|
||||
description: 'Arthur Danjou\'s educational background, including degrees, institutions, and academic achievements',
|
||||
uri: 'resource://artmcp/education',
|
||||
cache: '1 hour',
|
||||
handler: async (uri: URL) => {
|
||||
const event = useEvent()
|
||||
|
||||
const result = await queryCollection(event, 'education')
|
||||
.where('extension', '=', 'md')
|
||||
.select([
|
||||
'degree',
|
||||
'institution',
|
||||
'startDate',
|
||||
'endDate',
|
||||
'location'
|
||||
])
|
||||
.orderBy('startDate', 'desc')
|
||||
.all()
|
||||
|
||||
return {
|
||||
contents: [{
|
||||
uri: uri.toString(),
|
||||
mimeType: 'text/json',
|
||||
text: JSON.stringify(result)
|
||||
}]
|
||||
}
|
||||
}
|
||||
})
|
||||
31
server/mcp/resources/experiences.ts
Normal file
31
server/mcp/resources/experiences.ts
Normal file
@@ -0,0 +1,31 @@
|
||||
export default defineMcpResource({
|
||||
title: 'Arthur Danjou - Experiences',
|
||||
description: 'A detailed list of Arthur Danjou\'s professional work experiences, including roles, companies, and responsibilities',
|
||||
uri: 'resource://artmcp/experiences',
|
||||
cache: '1 hour',
|
||||
handler: async (uri: URL) => {
|
||||
const event = useEvent()
|
||||
|
||||
const result = await queryCollection(event, 'experiences')
|
||||
.where('extension', '=', 'md')
|
||||
.select([
|
||||
'title',
|
||||
'company',
|
||||
'companyUrl',
|
||||
'startDate',
|
||||
'endDate',
|
||||
'location',
|
||||
'description'
|
||||
])
|
||||
.orderBy('startDate', 'desc')
|
||||
.all()
|
||||
|
||||
return {
|
||||
contents: [{
|
||||
uri: uri.toString(),
|
||||
mimeType: 'text/json',
|
||||
text: JSON.stringify(result)
|
||||
}]
|
||||
}
|
||||
}
|
||||
})
|
||||
21
server/mcp/resources/hobbies.ts
Normal file
21
server/mcp/resources/hobbies.ts
Normal file
@@ -0,0 +1,21 @@
|
||||
export default defineMcpResource({
|
||||
title: 'Arthur Danjou - Hobbies & Interests',
|
||||
description: 'Arthur Danjou\'s personal hobbies, interests, and passions outside of professional work',
|
||||
uri: 'resource://artmcp/hobbies',
|
||||
cache: '1 hour',
|
||||
handler: async (uri: URL) => {
|
||||
const event = useEvent()
|
||||
|
||||
const result = await queryCollection(event, 'hobbies')
|
||||
.where('extension', '=', 'md')
|
||||
.first()
|
||||
|
||||
return {
|
||||
contents: [{
|
||||
uri: uri.toString(),
|
||||
mimeType: 'text/json',
|
||||
text: JSON.stringify(result.body, null, 2)
|
||||
}]
|
||||
}
|
||||
}
|
||||
})
|
||||
21
server/mcp/resources/languages.ts
Normal file
21
server/mcp/resources/languages.ts
Normal file
@@ -0,0 +1,21 @@
|
||||
export default defineMcpResource({
|
||||
title: 'Arthur Danjou - Spoken Languages & Proficiency Levels',
|
||||
description: 'Languages spoken by Arthur Danjou with detailed proficiency levels for each language',
|
||||
uri: 'resource://artmcp/languages',
|
||||
cache: '1 hour',
|
||||
handler: async (uri: URL) => {
|
||||
const event = useEvent()
|
||||
|
||||
const result = await queryCollection(event, 'languages')
|
||||
.where('extension', '=', 'json')
|
||||
.first()
|
||||
|
||||
return {
|
||||
contents: [{
|
||||
uri: uri.toString(),
|
||||
mimeType: 'text/json',
|
||||
text: JSON.stringify(result.body, null, 2)
|
||||
}]
|
||||
}
|
||||
}
|
||||
})
|
||||
21
server/mcp/resources/profile.ts
Normal file
21
server/mcp/resources/profile.ts
Normal file
@@ -0,0 +1,21 @@
|
||||
export default defineMcpResource({
|
||||
title: 'Arthur Danjou - Professional Profile',
|
||||
description: 'Comprehensive professional profile of Arthur Danjou, including biography, location, availability status, career goals, and work preferences',
|
||||
uri: 'resource://artmcp/profile',
|
||||
cache: '1 hour',
|
||||
handler: async (uri: URL) => {
|
||||
const event = useEvent()
|
||||
|
||||
const result = await queryCollection(event, 'profile')
|
||||
.where('extension', '=', 'md')
|
||||
.first()
|
||||
|
||||
return {
|
||||
contents: [{
|
||||
uri: uri.toString(),
|
||||
mimeType: 'text/json',
|
||||
text: JSON.stringify(result)
|
||||
}]
|
||||
}
|
||||
}
|
||||
})
|
||||
21
server/mcp/resources/projects.ts
Normal file
21
server/mcp/resources/projects.ts
Normal file
@@ -0,0 +1,21 @@
|
||||
export default defineMcpResource({
|
||||
title: 'Arthur Danjou - Projects Portfolio',
|
||||
description: 'A comprehensive collection of projects developed by Arthur Danjou, showcasing technical skills and achievements',
|
||||
uri: 'resource://artmcp/projects',
|
||||
cache: '1 hour',
|
||||
handler: async (uri: URL) => {
|
||||
const event = useEvent()
|
||||
|
||||
const result = await queryCollection(event, 'projects')
|
||||
.where('extension', '=', 'md')
|
||||
.all()
|
||||
|
||||
return {
|
||||
contents: [{
|
||||
uri: uri.toString(),
|
||||
mimeType: 'text/json',
|
||||
text: JSON.stringify(result)
|
||||
}]
|
||||
}
|
||||
}
|
||||
})
|
||||
21
server/mcp/resources/skills.ts
Normal file
21
server/mcp/resources/skills.ts
Normal file
@@ -0,0 +1,21 @@
|
||||
export default defineMcpResource({
|
||||
title: 'Arthur Danjou - Skills',
|
||||
description: 'A comprehensive list of technical skills, programming languages, frameworks, and tools mastered by Arthur Danjou',
|
||||
cache: '1 hour',
|
||||
uri: 'resource://artmcp/skills',
|
||||
handler: async () => {
|
||||
const event = useEvent()
|
||||
|
||||
const result = await queryCollection(event, 'skills')
|
||||
.where('extension', '=', 'json')
|
||||
.first()
|
||||
|
||||
return {
|
||||
contents: [{
|
||||
uri: result.path,
|
||||
mimeType: 'text/json',
|
||||
text: JSON.stringify(result.body, null, 2)
|
||||
}]
|
||||
}
|
||||
}
|
||||
})
|
||||
31
server/mcp/resources/uses.ts
Normal file
31
server/mcp/resources/uses.ts
Normal file
@@ -0,0 +1,31 @@
|
||||
export default defineMcpResource({
|
||||
title: 'Arthur Danjou - Tech Stack & Tools',
|
||||
description: 'A curated list of tools, software, and hardware used by Arthur Danjou, organized by categories (homelab, IDE, hardware, software)',
|
||||
uri: 'resource://artmcp/uses',
|
||||
cache: '1 hour',
|
||||
handler: async (uri: URL) => {
|
||||
const event = useEvent()
|
||||
|
||||
const categories = await queryCollection(event, 'usesCategories').where('extension', '=', 'md').all()
|
||||
|
||||
const uses = await queryCollection(event, 'uses')
|
||||
.where('extension', '=', 'md')
|
||||
.all()
|
||||
|
||||
const uses_by_categories = []
|
||||
for (const category of categories) {
|
||||
uses_by_categories.push({
|
||||
category: category,
|
||||
uses: uses.filter((use: { category: unknown }) => use.category === category.slug)
|
||||
})
|
||||
}
|
||||
|
||||
return {
|
||||
contents: [{
|
||||
uri: uri.toString(),
|
||||
mimeType: 'text/json',
|
||||
text: JSON.stringify(uses_by_categories, null, 2)
|
||||
}]
|
||||
}
|
||||
}
|
||||
})
|
||||
12
server/mcp/tools/activity.ts
Normal file
12
server/mcp/tools/activity.ts
Normal file
@@ -0,0 +1,12 @@
|
||||
export default defineMcpTool({
|
||||
description: 'Real-time current activity and status of Arthur Danjou, including what he\'s currently working on',
|
||||
handler: async () => {
|
||||
const result = await $fetch('/api/activity')
|
||||
return {
|
||||
content: [{
|
||||
type: 'text',
|
||||
text: JSON.stringify(result, null, 2)
|
||||
}]
|
||||
}
|
||||
}
|
||||
})
|
||||
15
server/mcp/tools/resume-link.ts
Normal file
15
server/mcp/tools/resume-link.ts
Normal file
@@ -0,0 +1,15 @@
|
||||
import z from 'zod'
|
||||
|
||||
export default defineMcpTool({
|
||||
description: 'Retrieves a direct download link to Arthur Danjou\'s professional resume in the specified language. Supports both English and French versions.',
|
||||
inputSchema: {
|
||||
lang: z.enum(['en', 'fr']).describe('The language for the resume: \'en\' for English or \'fr\' for French.')
|
||||
},
|
||||
handler: async ({ lang }) => {
|
||||
const base_url = import.meta.dev ? 'http://localhost:3000/api' : 'https://mcp.arthurdanjou.fr/api'
|
||||
const url = `${base_url}/resumes/${lang}`
|
||||
return {
|
||||
content: [{ type: 'text', text: JSON.stringify(url, null, 2) }]
|
||||
}
|
||||
}
|
||||
})
|
||||
12
server/mcp/tools/stats.ts
Normal file
12
server/mcp/tools/stats.ts
Normal file
@@ -0,0 +1,12 @@
|
||||
export default defineMcpTool({
|
||||
description: 'Detailed coding statistics and analytics from WakaTime, including programming languages, time spent coding, and productivity metrics',
|
||||
handler: async () => {
|
||||
const result = await $fetch('/api/wakatime')
|
||||
return {
|
||||
content: [{
|
||||
type: 'text',
|
||||
text: JSON.stringify(result, null, 2)
|
||||
}]
|
||||
}
|
||||
}
|
||||
})
|
||||
12
server/mcp/tools/status-page.ts
Normal file
12
server/mcp/tools/status-page.ts
Normal file
@@ -0,0 +1,12 @@
|
||||
export default defineMcpTool({
|
||||
description: 'Real-time status, uptime monitoring, and incident reports for Arthur Danjou\'s homelab infrastructure, powered by UptimeKuma',
|
||||
handler: async () => {
|
||||
const result = await $fetch('/api/status-page')
|
||||
return {
|
||||
content: [{
|
||||
type: 'text',
|
||||
text: JSON.stringify(result, null, 2)
|
||||
}]
|
||||
}
|
||||
}
|
||||
})
|
||||
21
server/mcp/tools/uses-by-category.ts
Normal file
21
server/mcp/tools/uses-by-category.ts
Normal file
@@ -0,0 +1,21 @@
|
||||
import z from 'zod'
|
||||
|
||||
export default defineMcpTool({
|
||||
description: 'Retrieves a filtered list of tools, software, and hardware used by Arthur Danjou based on a specific category. Available categories: homelab, IDE, hardware, and software.',
|
||||
inputSchema: {
|
||||
categoryName: z.enum(['homelab', 'ide', 'hardware', 'software']).describe('The category to filter by: \'homelab\', \'ide\', \'hardware\', or \'software\'.')
|
||||
},
|
||||
handler: async ({ categoryName }) => {
|
||||
const event = useEvent()
|
||||
|
||||
const result = await queryCollection(event, 'uses')
|
||||
.where('extension', '=', 'md')
|
||||
.where('category', '=', categoryName)
|
||||
.all()
|
||||
|
||||
return {
|
||||
content: [{ type: 'text', text: JSON.stringify(result, null, 2) }],
|
||||
structuredContent: result as { [key: string]: unknown }
|
||||
}
|
||||
}
|
||||
})
|
||||
30
server/mcp/tools/weather.ts
Normal file
30
server/mcp/tools/weather.ts
Normal file
@@ -0,0 +1,30 @@
|
||||
import { z } from 'zod'
|
||||
|
||||
export default defineMcpTool({
|
||||
description: 'Get current weather for a city',
|
||||
inputSchema: {
|
||||
city: z.string().describe('City name')
|
||||
},
|
||||
cache: '15m',
|
||||
handler: async ({ city }) => {
|
||||
try {
|
||||
const data = await $fetch(`https://wttr.in/${city}?format=j1`)
|
||||
|
||||
return {
|
||||
content: [{
|
||||
type: 'text',
|
||||
text: JSON.stringify(data, null, 2)
|
||||
}]
|
||||
}
|
||||
}
|
||||
catch (error) {
|
||||
return {
|
||||
content: [{
|
||||
type: 'text',
|
||||
text: `Error: ${error instanceof Error ? error.message : String(error)}`
|
||||
}],
|
||||
isError: true
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
Reference in New Issue
Block a user