diff --git a/README.md b/README.md index b94a89b..5463d5e 100644 --- a/README.md +++ b/README.md @@ -1,35 +1,89 @@ -# Hello Edge +# ArtMCP - Arthur Danjou's MCP Server -A minimal [Nuxt](https://nuxt.com) starter deployed on the Edge using [NuxtHub](https://hub.nuxt.com). +A comprehensive [Model Context Protocol (MCP)](https://modelcontextprotocol.io) server exposing professional profile information about Arthur Danjou. Built with [Nuxt](https://nuxt.com) and deployed on [NuxtHub](https://hub.nuxt.com) at the Edge. -https://hello.nuxt.dev +๐Ÿ”— **Live Server**: https://mcp.arthurdanjou.fr - -Hello World template for NuxtHub - +## ๐ŸŽฏ Features -## Features +### MCP Resources -- Server-Side rendering on Cloudflare Workers -- ESLint setup -- Ready to add a database, blob and KV storage -- One click deploy on 275+ locations for free +The server exposes the following resources through the Model Context Protocol: -## Setup +- **๐Ÿ“Š Skills** (`resource://artmcp/skills`) - Complete list of technical skills (programming languages, frameworks, tools) +- **๐Ÿ’ผ Experiences** (`resource://artmcp/experiences`) - Professional work experience and projects +- **๐Ÿš€ Projects** (`resource://artmcp/projects`) - Portfolio of personal and professional projects +- **๐ŸŽ“ Education** (`resource://artmcp/education`) - Academic background and degrees +- **๐ŸŒ Languages** (`resource://artmcp/languages`) - Spoken languages with proficiency levels +- **๐Ÿ† Certifications** (`resource://artmcp/certifications`) - Professional certifications and achievements +- **๐Ÿ‘ค Profile** (`resource://artmcp/profile`) - Comprehensive profile with bio, location, availability, career goals, and work preferences +- **๐ŸŽจ Hobbies** (`resource://artmcp/hobbies`) - Personal interests and activities +- **๐Ÿ“ž Contact** (`resource://artmcp/contact`) - Professional contact information and social links +- **๐Ÿ› ๏ธ Uses** (`resource://artmcp/uses`) - Tools, hardware, and software setup +- **๐Ÿ“ˆ Activity** (`resource://artmcp/activity`) - Real-time coding activity (Discord integration) +- **โฑ๏ธ Wakatime** (`resource://artmcp/wakatime`) - Coding statistics powered by Wakatime +- **๐Ÿ  Status Page** (`resource://artmcp/status_page`) - Homelab services uptime and incidents -Make sure to install the dependencies with [pnpm](https://pnpm.io/installation#using-corepack): +### MCP Tools + +- **`get_resume_link`** - Get download link for resume in English or French +- **`get_uses_by_category`** - Filter uses by category (homelab, ide, hardware, software) + +### MCP Prompts + +Pre-configured prompts for common queries about: +- Resume generation +- Skills and expertise +- Projects showcase +- Real-time activity +- Contact information +- And more... + +## ๐Ÿ—๏ธ Architecture + +This project uses: +- **Nuxt 4** with Nitro for server-side rendering +- **@nuxt/content** for content management +- **@modelcontextprotocol/sdk** for MCP server implementation +- **NuxtHub** for edge deployment on Cloudflare Workers +- **Zod** for schema validation + +## ๐Ÿš€ Getting Started + +### Prerequisites + +- Node.js 18+ or Bun +- pnpm 10.12.1+ + +### Installation ```bash +# Install dependencies pnpm install ``` -You can update the main text displayed by creating a `.env`: +### Environment Variables + +Create a `.env` file (optional): ```bash -NUXT_PUBLIC_HELLO_TEXT="Hello my world!" +# Discord integration (optional) +NUXT_DISCORD_USER_ID="" +NUXT_DISCORD_ID="" +NUXT_DISCORD_TOKEN="" + +# Wakatime integration (optional) +NUXT_WAKATIME_USER_ID="" +NUXT_WAKATIME_CODING="" +NUXT_WAKATIME_EDITORS="" +NUXT_WAKATIME_LANGUAGES="" +NUXT_WAKATIME_OS="" + +# Status page (optional) +NUXT_STATUS_PAGE="" ``` -## Development Server +### Development Start the development server on `http://localhost:3000`: @@ -37,7 +91,7 @@ Start the development server on `http://localhost:3000`: pnpm dev ``` -## Production +### Production Build the application for production: @@ -45,16 +99,112 @@ Build the application for production: pnpm build ``` -## Deploy +### Deployment - -Deploy the application on the Edge with [NuxtHub](https://hub.nuxt.com) on your Cloudflare account: +Deploy to NuxtHub/Cloudflare: ```bash -npx nuxthub deploy +pnpm deploy ``` -Then checkout your server logs, analaytics and more in the [NuxtHub Admin](https://admin.hub.nuxt.com). +## ๐Ÿ“š API Endpoints -You can also deploy using [Cloudflare Pages CI](https://hub.nuxt.com/docs/getting-started/deploy#cloudflare-pages-ci). +All resources are also available as REST API endpoints: + +- `GET /api/skills` +- `GET /api/experiences` +- `GET /api/projects` +- `GET /api/educations` +- `GET /api/languages` +- `GET /api/certifications` +- `GET /api/mathematics` +- `GET /api/profile` +- `GET /api/hobbies` +- `GET /api/contact` +- `GET /api/uses` +- `GET /api/uses_by_category?categoryName={category}` +- `GET /api/activity` +- `GET /api/wakatime` +- `GET /api/status_page` +- `GET /api/resumes/{en|fr}` - Download resume + +## ๐Ÿงช Development + +### Linting + +```bash +pnpm lint +``` + +### Type Checking + +```bash +npx tsc --noEmit --skipLibCheck +``` + +## ๐Ÿ“‚ Content Structure + +Content is managed in the `content/` directory: + +``` +content/ +โ”œโ”€โ”€ skills.json # Technical skills +โ”œโ”€โ”€ languages.json # Spoken languages +โ”œโ”€โ”€ certifications.json # Professional certifications +โ”œโ”€โ”€ mathematics.json # Mathematics background +โ”œโ”€โ”€ profile.json # Comprehensive profile info +โ”œโ”€โ”€ contact.json # Contact information +โ”œโ”€โ”€ hobbies.md # Personal interests +โ”œโ”€โ”€ experiences/*.md # Work experiences +โ”œโ”€โ”€ projects/*.md # Project portfolio +โ”œโ”€โ”€ education/*.md # Academic background +โ””โ”€โ”€ uses/*.md # Tools and setup +``` + +## ๐Ÿ”ง Technologies + +- **Frontend/Backend**: Nuxt 4, Vue 3, Nitro +- **MCP**: Model Context Protocol SDK +- **Content**: Nuxt Content with better-sqlite3 +- **Deployment**: Cloudflare Workers via NuxtHub +- **Validation**: Zod schemas + +## ๐Ÿ“– MCP Integration + +To use this server with an MCP client: + +1. Configure your MCP client to connect to `https://mcp.arthurdanjou.fr/mcp` +2. Or use the API directly via REST endpoints + +Example MCP client configuration: +```json +{ + "mcpServers": { + "artmcp": { + "url": "https://mcp.arthurdanjou.fr/mcp" + } + } +} +``` + +## ๐Ÿค Contributing + +This is a personal portfolio project. Feel free to use it as inspiration for your own MCP server! + +## ๐Ÿ“ License + +Private project - All rights reserved + +## ๐Ÿ‘ค About + +**Arthur Danjou** +- Software Engineer & Mathematics Student +- ๐Ÿ“ Paris, France +- ๐Ÿ”— [LinkedIn](https://go.arthurdanjou.fr/linkedin) +- ๐Ÿ™ [GitHub](https://go.arthurdanjou.fr/github) +- ๐Ÿ“ง [Email](https://go.arthurdanjou.fr/mail-pro) + +--- + +Built with โค๏ธ using Nuxt and the Model Context Protocol diff --git a/content.config.ts b/content.config.ts index 0958c7c..a56ea94 100644 --- a/content.config.ts +++ b/content.config.ts @@ -79,13 +79,46 @@ export default defineContentConfig({ schema: z.object({ body: z.array(z.object({ name: z.string(), - url: z.string().url() + icon: z.string().optional(), + value: z.string().url(), + username: z.string().optional() })) }) }), hobbies: defineCollection({ type: 'page', source: 'hobbies.md' + }), + languages: defineCollection({ + type: 'page', + source: 'languages.json', + schema: z.object({ + body: z.array(z.object({ + name: z.string(), + level: z.string(), + proficiency: z.string() + })) + }) + }), + certifications: defineCollection({ + type: 'page', + source: 'certifications.json', + schema: z.object({ + body: z.array(z.object({ + name: z.string(), + issuer: z.string(), + date: z.string(), + url: z.string().url().optional() + })) + }) + }), + mathematics: defineCollection({ + type: 'page', + source: 'mathematics.md' + }), + profile: defineCollection({ + type: 'page', + source: 'profile.md' }) } }) diff --git a/content/certifications.json b/content/certifications.json new file mode 100644 index 0000000..5df598c --- /dev/null +++ b/content/certifications.json @@ -0,0 +1,22 @@ +TODO: complete + +{ + "body": [ + { + "name": "Git & GitHub", + "issuer": "GitHub Learning Lab", + "date": "2021-06", + "url": "https://github.com" + }, + { + "name": "Docker Essentials", + "issuer": "Self-taught through practical experience", + "date": "2021-09" + }, + { + "name": "Machine Learning Specialization", + "issuer": "Various academic courses", + "date": "2024-09" + } + ] +} diff --git a/content/contact.json b/content/contact.json index 9523e01..42b9e03 100644 --- a/content/contact.json +++ b/content/contact.json @@ -18,7 +18,8 @@ { "name": "GitHub", "icon": "i-ph:github-logo-duotone", - "value": "https://go.arthurdanjou.fr/github" + "value": "https://go.arthurdanjou.fr/github", + "username": "ArthurDanjou" }, { "name": "Twitter", @@ -29,6 +30,21 @@ "name": "Discord", "icon": "i-ph:discord-logo-duotone", "value": "https://go.arthurdanjou.fr/discord" + }, + { + "name": "Personal Website", + "icon": "i-ph:globe-duotone", + "value": "https://arthurdanjou.fr" + }, + { + "name": "MCP Server", + "icon": "i-ph:globe-duotone", + "value": "https://mcp.arthurdanjou.fr" + }, + { + "name": "Status Page", + "icon": "i-ph:fire-duotone", + "value": "https://go.arthurdanjou.fr/status" } ] } \ No newline at end of file diff --git a/content/languages.json b/content/languages.json new file mode 100644 index 0000000..f068fa1 --- /dev/null +++ b/content/languages.json @@ -0,0 +1,19 @@ +{ + "body": [ + { + "name": "French", + "level": "Native", + "proficiency": "C2" + }, + { + "name": "English", + "level": "Fluent", + "proficiency": "C1" + }, + { + "name": "Spanish", + "level": "Intermediate", + "proficiency": "A2" + } + ] +} diff --git a/content/mathematics.md b/content/mathematics.md new file mode 100644 index 0000000..a842f29 --- /dev/null +++ b/content/mathematics.md @@ -0,0 +1 @@ +TODO: complete \ No newline at end of file diff --git a/content/profile.md b/content/profile.md new file mode 100644 index 0000000..6afde07 --- /dev/null +++ b/content/profile.md @@ -0,0 +1,34 @@ +TODO: complete and convert + +{ + "shortBio": "Software Engineer & Mathematics Student passionate about AI, Data Science, and Infrastructure. Building scalable solutions at the intersection of theory and practice.", + "location": { + "current": "Paris, France", + "timezone": "Europe/Paris (CET/CEST)", + "remote": true + }, + "availability": { + "status": "open_to_opportunities", + "types": ["internship", "full-time", "part-time", "freelance"], + "preferences": ["remote", "hybrid"], + "startDate": "2025-06" + }, + "careerGoals": [ + "Become an expert in Machine Learning Engineering and MLOps", + "Contribute to open-source AI/ML projects", + "Build scalable data infrastructure for real-world applications", + "Combine mathematical rigor with practical engineering solutions" + ], + "workPreferences": { + "workStyle": ["remote", "hybrid"], + "companySize": ["startup", "scale-up", "enterprise"], + "industries": ["AI/ML", "Data Science", "FinTech", "SaaS", "DevOps"], + "roles": ["Machine Learning Engineer", "Data Engineer", "Software Engineer", "MLOps Engineer"] + }, + "achievements": [ + "Built and maintained personal homelab with 10+ self-hosted services", + "Developed mini-games for Erisium, one of the largest French-speaking Minecraft servers", + "Created multiple full-stack applications using modern web technologies", + "Active contributor to various technical projects and communities" + ] +} diff --git a/nuxt.config.ts b/nuxt.config.ts index d25b43d..2080d89 100644 --- a/nuxt.config.ts +++ b/nuxt.config.ts @@ -41,7 +41,6 @@ export default defineNuxtConfig({ database: true, ai: true, analytics: true, - kv: true, cache: true }, diff --git a/server/api/certifications.get.ts b/server/api/certifications.get.ts new file mode 100644 index 0000000..4ac26d3 --- /dev/null +++ b/server/api/certifications.get.ts @@ -0,0 +1,10 @@ +import { queryCollection } from '@nuxt/content/server' + +export default defineCachedEventHandler(async (event) => { + return await queryCollection(event, 'certifications') + .where('extension', '=', 'json') + .first() +}, { + name: 'certifications-list', + maxAge: 3600 // 1 hour +}) diff --git a/server/api/languages.get.ts b/server/api/languages.get.ts new file mode 100644 index 0000000..665bda8 --- /dev/null +++ b/server/api/languages.get.ts @@ -0,0 +1,10 @@ +import { queryCollection } from '@nuxt/content/server' + +export default defineCachedEventHandler(async (event) => { + return await queryCollection(event, 'languages') + .where('extension', '=', 'json') + .first() +}, { + name: 'languages-list', + maxAge: 3600 // 1 hour +}) diff --git a/server/api/mathematics.get.ts b/server/api/mathematics.get.ts new file mode 100644 index 0000000..c4cc32f --- /dev/null +++ b/server/api/mathematics.get.ts @@ -0,0 +1,10 @@ +import { queryCollection } from '@nuxt/content/server' + +export default defineCachedEventHandler(async (event) => { + return await queryCollection(event, 'mathematics') + .where('extension', '=', 'md') + .first() +}, { + name: 'mathematics-list', + maxAge: 3600 // 1 hour +}) diff --git a/server/api/profile.get.ts b/server/api/profile.get.ts new file mode 100644 index 0000000..8874a0b --- /dev/null +++ b/server/api/profile.get.ts @@ -0,0 +1,10 @@ +import { queryCollection } from '@nuxt/content/server' + +export default defineCachedEventHandler(async (event) => { + return await queryCollection(event, 'profile') + .where('extension', '=', 'md') + .first() +}, { + name: 'profile-info', + maxAge: 3600 // 1 hour +}) diff --git a/server/routes/mcp.ts b/server/routes/mcp.ts index 2821751..a7be60b 100644 --- a/server/routes/mcp.ts +++ b/server/routes/mcp.ts @@ -146,8 +146,8 @@ function createServer() { 'artmcp-contact', 'resource://artmcp/contact', { - title: 'Arthur Danjou - Contact Information', - description: 'Contact details for Arthur Danjou, including email, social media profiles, and other communication channels' + title: 'ArtMCP Contact', + description: 'Get Contact Information and Social Links of Arthur Danjou including email, LinkedIn, GitHub, Twitter, Discord, and websites' }, async (uri) => { const result = await $fetch('/api/contact') @@ -199,6 +199,82 @@ function createServer() { } ) + server.registerResource( + 'artmcp-languages', + 'resource://artmcp/languages', + { + title: 'Arthur Danjou - Languages', + description: 'Get Languages spoken by Arthur Danjou with proficiency levels' + }, + async (uri) => { + const result = await $fetch('/api/languages') + return { + contents: [{ + uri: uri.href, + mimeType: 'application/json', + text: JSON.stringify(result, null, 2) + }] + } + } + ) + + server.registerResource( + 'artmcp-certifications', + 'resource://artmcp/certifications', + { + title: 'Arthur Danjou - Certifications', + description: 'Get Certifications and achievements of Arthur Danjou' + }, + async (uri) => { + const result = await $fetch('/api/certifications') + return { + contents: [{ + uri: uri.href, + mimeType: 'application/json', + text: JSON.stringify(result, null, 2) + }] + } + } + ) + + server.registerResource( + 'artmcp-mathematics', + 'resource://artmcp/mathematics', + { + title: 'Arthur Danjou - Mathematics', + description: 'Get information about Arthur Danjou\'s background and knowledge in mathematics, including areas of expertise and academic achievements' + }, + async (uri) => { + const result = await $fetch('/api/mathematics') + return { + contents: [{ + uri: uri.href, + mimeType: 'application/json', + text: JSON.stringify(result, null, 2) + }] + } + } + ) + + server.registerResource( + 'artmcp-profile', + 'resource://artmcp/profile', + { + title: 'Arthur Danjou - Profile', + description: 'Get comprehensive profile information of Arthur Danjou including bio, location, availability, career goals, and work preferences' + }, + async (uri) => { + const result = await $fetch('/api/profile') + return { + contents: [{ + uri: uri.href, + mimeType: 'application/json', + text: JSON.stringify(result, null, 2) + }] + } + } + ) + // Tools server.registerTool( 'get_resume_link', @@ -303,8 +379,8 @@ function createServer() { server.registerPrompt( 'artmcp-contact', { - title: 'Request Contact Information', - description: 'Generate a prompt to retrieve Arthur Danjou\'s contact details and communication channels.' + title: 'Get Contact Information and Social Links of Arthur Danjou', + description: 'Get Contact Information and Social Links of Arthur Danjou including email, social media, and websites' }, async () => { return { @@ -312,7 +388,7 @@ function createServer() { role: 'user', content: { type: 'text', - text: `How can I contact Arthur Danjou?` + text: `How can I contact Arthur Danjou? Provide all contact methods and social links.` } }] } @@ -420,6 +496,82 @@ function createServer() { } ) + server.registerPrompt( + 'artmcp-languages', + { + title: 'Get Languages of Arthur Danjou', + description: 'Get Languages spoken by Arthur Danjou with proficiency levels' + }, + async () => { + return { + messages: [{ + role: 'user', + content: { + type: 'text', + text: `What languages does Arthur Danjou speak and at what proficiency level?` + } + }] + } + } + ) + + server.registerPrompt( + 'artmcp-certifications', + { + title: 'Get Certifications of Arthur Danjou', + description: 'Get Certifications and achievements of Arthur Danjou' + }, + async () => { + return { + messages: [{ + role: 'user', + content: { + type: 'text', + text: `What certifications and professional achievements does Arthur Danjou have?` + } + }] + } + } + ) + + server.registerPrompt( + 'artmcp-mathematics', + { + title: 'Get Mathematical Background Knowledge of Arthur Danjou', + description: 'Get information about Arthur Danjou\'s background and knowledge in mathematics, including areas of expertise and academic achievements' + }, + async () => { + return { + messages: [{ + role: 'user', + content: { + type: 'text', + text: `Provide me information about Arthur Danjou's background and knowledge in mathematics, including areas of expertise and academic achievements.` + } + }] + } + } + ) + + server.registerPrompt( + 'artmcp-profile', + { + title: 'Get Profile Information of Arthur Danjou', + description: 'Get comprehensive profile information including bio, location, availability, and career goals' + }, + 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.` + } + }] + } + } + ) + return server }