Merge pull request #5 from ArthurDanjou/copilot/add-documentation-for-mcp

Add MCP documentation page with tools, prompts and resources
This commit is contained in:
2025-11-30 15:48:27 +01:00
committed by GitHub
22 changed files with 19124 additions and 110 deletions

View File

@@ -1,48 +1,134 @@
<script setup lang="ts">
const runtimeConfig = useRuntimeConfig()
const colors = ['#f87171', '#fb923c', '#fbbf24', '#facc15', '#a3e635', '#4ade80', '#34d399', '#2dd4bf', '#22d3ee', '#38bdf8', '#60a5fa', '#818cf8', '#a78bfa', '#c084fc', '#e879f9', '#f472b6', '#fb7185']
const color = useState('color', () => colors[Math.floor(Math.random() * colors.length)])
const { data: documentation } = await useAsyncData('documentation', () =>
queryCollection('documentation').first()
)
</script>
<template>
<div class="centered">
<h1 :style="{ color }">
{{ runtimeConfig.public.helloText }}
</h1>
<NuxtLink
to="/"
external
<div class="documentation-page">
<ContentRenderer
v-if="documentation"
:value="documentation"
class="content"
/>
<div
v-else
class="loading"
>
refresh
</NuxtLink>
Loading documentation...
</div>
</div>
</template>
<style scoped>
.centered {
position: absolute;
width: 100%;
text-align: center;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
margin: 0;
.documentation-page {
max-width: 800px;
margin: 0 auto;
padding: 2rem;
font-family: system-ui, -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, 'Open Sans', 'Helvetica Neue', sans-serif;
line-height: 1.6;
color: #333;
}
h1 {
font-size: 32px;
.loading {
text-align: center;
padding: 2rem;
color: #666;
}
@media (min-width: 768px) {
h1 {
font-size: 64px;
}
.content :deep(h1) {
font-size: 2.5rem;
margin-bottom: 1rem;
color: #1a1a1a;
border-bottom: 2px solid #e5e5e5;
padding-bottom: 0.5rem;
}
a {
color: #888;
.content :deep(h2) {
font-size: 1.75rem;
margin-top: 2rem;
margin-bottom: 1rem;
color: #2a2a2a;
}
.content :deep(h3) {
font-size: 1.25rem;
margin-top: 1.5rem;
margin-bottom: 0.5rem;
color: #3a3a3a;
}
.content :deep(p) {
margin-bottom: 1rem;
}
.content :deep(hr) {
border: none;
border-top: 1px solid #e5e5e5;
margin: 2rem 0;
}
.content :deep(code) {
background-color: #f5f5f5;
padding: 0.2em 0.4em;
border-radius: 3px;
font-size: 0.9em;
font-family: 'SFMono-Regular', Consolas, 'Liberation Mono', Menlo, monospace;
}
.content :deep(pre) {
background-color: #1e1e1e;
color: #d4d4d4;
padding: 1rem;
border-radius: 6px;
overflow-x: auto;
margin: 1rem 0;
}
.content :deep(pre code) {
background-color: transparent;
padding: 0;
color: inherit;
}
.content :deep(ul),
.content :deep(ol) {
margin-bottom: 1rem;
padding-left: 1.5rem;
}
.content :deep(li) {
margin-bottom: 0.5rem;
}
.content :deep(a) {
color: #0066cc;
text-decoration: none;
font-size: 18px;
}
a:hover {
.content :deep(a:hover) {
text-decoration: underline;
}
.content :deep(strong) {
font-weight: 600;
}
@media (max-width: 768px) {
.documentation-page {
padding: 1rem;
}
.content :deep(h1) {
font-size: 1.75rem;
}
.content :deep(h2) {
font-size: 1.5rem;
}
.content :deep(h3) {
font-size: 1.1rem;
}
}
</style>

View File

@@ -103,6 +103,10 @@ export default defineContentConfig({
profile: defineCollection({
type: 'page',
source: 'profile.md'
}),
documentation: defineCollection({
type: 'page',
source: 'documentation.md'
})
}
})

164
content/documentation.md Normal file
View File

@@ -0,0 +1,164 @@
---
title: ArtMCP Documentation
description: Documentation for ArtMCP - Arthur Danjou's Model Context Protocol Server
---
# ArtMCP Documentation
Welcome to **ArtMCP**, 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.
## Overview
ArtMCP provides AI assistants and applications with structured access to Arthur Danjou's professional information through the Model Context Protocol. This includes profile data, skills, experiences, projects, and real-time activity information.
---
## Tools
Tools are executable functions that AI assistants can call to perform actions or retrieve dynamic data.
### `activity`
**Description:** Real-time current activity and status of Arthur Danjou, including what he's currently working on.
### `resume-link`
**Description:** Retrieves a direct download link to Arthur Danjou's professional resume in the specified language.
- **Input:** `lang` - The language for the resume: `'en'` for English or `'fr'` for French.
### `stats`
**Description:** Detailed coding statistics and analytics from WakaTime, including programming languages, time spent coding, and productivity metrics.
### `status-page`
**Description:** Real-time status, uptime monitoring, and incident reports for Arthur Danjou's homelab infrastructure, powered by UptimeKuma.
### `uses-by-category`
**Description:** Retrieves a filtered list of tools, software, and hardware used by Arthur Danjou based on a specific category.
- **Input:** `categoryName` - The category to filter by: `'homelab'`, `'ide'`, `'hardware'`, or `'software'`.
### `weather`
**Description:** Get current weather for a city.
- **Input:** `city` - City name.
---
## Prompts
Prompts are pre-configured conversation starters that guide AI assistants on how to query specific information.
### `activity`
**Description:** Generates a prompt to retrieve Arthur Danjou's current real-time activity status, including what he is currently working on.
### `contact`
**Description:** Generates a prompt to retrieve Arthur Danjou's contact information and social media links, including email, LinkedIn, GitHub, Twitter, Discord, and personal websites.
### `hobbies`
**Description:** Generates a prompt to retrieve information about Arthur Danjou's personal hobbies, interests, and passions outside of professional work.
### `languages`
**Description:** Generates a prompt to retrieve the languages spoken by Arthur Danjou along with detailed proficiency levels for each language.
### `profile`
**Description:** Generates a prompt to retrieve comprehensive professional profile information about Arthur Danjou, including biography, location, availability status, career goals, and work preferences.
### `projects`
**Description:** Generates a prompt to retrieve a comprehensive list of personal and professional projects developed by Arthur Danjou, showcasing his technical skills and achievements.
### `resume`
**Description:** Generates a prompt to request and retrieve Arthur Danjou's professional resume in the specified language.
- **Input:** `lang` - The language for the resume: `'en'` for English or `'fr'` for French.
### `skills`
**Description:** Generates a prompt to retrieve a comprehensive list of technical skills, programming languages, frameworks, and tools mastered by Arthur Danjou.
### `stats`
**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.
### `status-page`
**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.
### `uses-by-category`
**Description:** Generates a prompt to retrieve tools, software, and hardware used by Arthur Danjou, filtered by a specific category.
- **Input:** `categoryName` - The category to filter by: `'homelab'`, `'ide'`, `'hardware'`, or `'software'`.
---
## Resources
Resources are static or semi-static data endpoints that provide structured information about Arthur Danjou.
### `resource://artmcp/profile`
**Title:** Arthur Danjou - Professional Profile
**Description:** Comprehensive professional profile of Arthur Danjou, including biography, location, availability status, career goals, and work preferences.
### `resource://artmcp/contact`
**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.
### `resource://artmcp/education`
**Title:** Arthur Danjou - Education & Academic Background
**Description:** Arthur Danjou's educational background, including degrees, institutions, and academic achievements.
### `resource://artmcp/experiences`
**Title:** Arthur Danjou - Experiences
**Description:** A detailed list of Arthur Danjou's professional work experiences, including roles, companies, and responsibilities.
### `resource://artmcp/hobbies`
**Title:** Arthur Danjou - Hobbies & Interests
**Description:** Arthur Danjou's personal hobbies, interests, and passions outside of professional work.
### `resource://artmcp/languages`
**Title:** Arthur Danjou - Spoken Languages & Proficiency Levels
**Description:** Languages spoken by Arthur Danjou with detailed proficiency levels for each language.
### `resource://artmcp/projects`
**Title:** Arthur Danjou - Projects Portfolio
**Description:** A comprehensive collection of projects developed by Arthur Danjou, showcasing technical skills and achievements.
### `resource://artmcp/skills`
**Title:** Arthur Danjou - Skills
**Description:** A comprehensive list of technical skills, programming languages, frameworks, and tools mastered by Arthur Danjou.
### `resource://artmcp/uses`
**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).
---
## MCP Integration
To use this server with an MCP client, configure your client to connect to:
```
https://mcp.arthurdanjou.fr/mcp
```
### Example Configuration
```json
{
"mcpServers": {
"artmcp": {
"url": "https://mcp.arthurdanjou.fr/mcp"
}
}
}
```
---
## API Endpoints
All resources are also available as REST API endpoints:
- `GET /api/profile` - Profile information
- `GET /api/contact` - Contact information
- `GET /api/skills` - Technical skills
- `GET /api/experiences` - Work experiences
- `GET /api/education` - Education background
- `GET /api/projects` - Projects portfolio
- `GET /api/languages` - Spoken languages
- `GET /api/hobbies` - Hobbies and interests
- `GET /api/uses` - Tech stack and tools
- `GET /api/activity` - Real-time activity
- `GET /api/wakatime` - Coding statistics
- `GET /api/status-page` - Status page
- `GET /api/resumes/{en|fr}` - Download resume

18731
package-lock.json generated Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,7 @@
export default defineEventHandler(async (event) => {
const result = await queryCollection(event, 'contact')
.where('extension', '=', 'json')
.first()
return result.body
})

View File

@@ -0,0 +1,15 @@
export default defineEventHandler(async (event) => {
const result = await queryCollection(event, 'education')
.where('extension', '=', 'md')
.all()
return result
.sort((a, b) => new Date(b.startDate).getTime() - new Date(a.startDate).getTime())
.map(edu => ({
degree: edu.degree,
institution: edu.institution,
startDate: edu.startDate,
endDate: edu.endDate,
location: edu.location
}))
})

View File

@@ -0,0 +1,17 @@
export default defineEventHandler(async (event) => {
const result = await queryCollection(event, 'experiences')
.where('extension', '=', 'md')
.all()
return result
.sort((a, b) => new Date(b.startDate).getTime() - new Date(a.startDate).getTime())
.map(exp => ({
title: exp.title,
company: exp.company,
companyUrl: exp.companyUrl,
startDate: exp.startDate,
endDate: exp.endDate,
location: exp.location,
description: exp.description
}))
})

View File

@@ -0,0 +1,7 @@
export default defineEventHandler(async (event) => {
const result = await queryCollection(event, 'hobbies')
.where('extension', '=', 'md')
.first()
return result.body
})

View File

@@ -0,0 +1,7 @@
export default defineEventHandler(async (event) => {
const result = await queryCollection(event, 'languages')
.where('extension', '=', 'json')
.first()
return result.body
})

View File

@@ -0,0 +1,7 @@
export default defineEventHandler(async (event) => {
const result = await queryCollection(event, 'profile')
.where('extension', '=', 'md')
.first()
return result
})

View File

@@ -0,0 +1,7 @@
export default defineEventHandler(async (event) => {
const result = await queryCollection(event, 'projects')
.where('extension', '=', 'md')
.all()
return result
})

7
server/api/skills.get.ts Normal file
View File

@@ -0,0 +1,7 @@
export default defineEventHandler(async (event) => {
const result = await queryCollection(event, 'skills')
.where('extension', '=', 'json')
.first()
return result.body
})

19
server/api/uses.get.ts Normal file
View File

@@ -0,0 +1,19 @@
export default defineEventHandler(async (event) => {
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 uses_by_categories
})

View File

@@ -4,17 +4,13 @@ export default defineMcpResource({
uri: 'resource://artmcp/contact',
cache: '1 hour',
handler: async (uri: URL) => {
const event = useEvent()
const result = await queryCollection(event, 'contact')
.where('extension', '=', 'json')
.first()
const result = await $fetch('/api/contact')
return {
contents: [{
uri: uri.toString(),
mimeType: 'text/json',
text: JSON.stringify(result.body, null, 2)
text: JSON.stringify(result, null, 2)
}]
}
}

View File

@@ -4,19 +4,7 @@ export default defineMcpResource({
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()
const result = await $fetch('/api/education')
return {
contents: [{

View File

@@ -4,21 +4,7 @@ export default defineMcpResource({
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()
const result = await $fetch('/api/experiences')
return {
contents: [{

View File

@@ -4,17 +4,13 @@ export default defineMcpResource({
uri: 'resource://artmcp/hobbies',
cache: '1 hour',
handler: async (uri: URL) => {
const event = useEvent()
const result = await queryCollection(event, 'hobbies')
.where('extension', '=', 'md')
.first()
const result = await $fetch('/api/hobbies')
return {
contents: [{
uri: uri.toString(),
mimeType: 'text/json',
text: JSON.stringify(result.body, null, 2)
text: JSON.stringify(result, null, 2)
}]
}
}

View File

@@ -4,17 +4,13 @@ export default defineMcpResource({
uri: 'resource://artmcp/languages',
cache: '1 hour',
handler: async (uri: URL) => {
const event = useEvent()
const result = await queryCollection(event, 'languages')
.where('extension', '=', 'json')
.first()
const result = await $fetch('/api/languages')
return {
contents: [{
uri: uri.toString(),
mimeType: 'text/json',
text: JSON.stringify(result.body, null, 2)
text: JSON.stringify(result, null, 2)
}]
}
}

View File

@@ -4,11 +4,7 @@ export default defineMcpResource({
uri: 'resource://artmcp/profile',
cache: '1 hour',
handler: async (uri: URL) => {
const event = useEvent()
const result = await queryCollection(event, 'profile')
.where('extension', '=', 'md')
.first()
const result = await $fetch('/api/profile')
return {
contents: [{

View File

@@ -4,11 +4,7 @@ export default defineMcpResource({
uri: 'resource://artmcp/projects',
cache: '1 hour',
handler: async (uri: URL) => {
const event = useEvent()
const result = await queryCollection(event, 'projects')
.where('extension', '=', 'md')
.all()
const result = await $fetch('/api/projects')
return {
contents: [{

View File

@@ -3,18 +3,14 @@ export default defineMcpResource({
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()
handler: async (uri: URL) => {
const result = await $fetch('/api/skills')
return {
contents: [{
uri: result.path,
uri: uri.toString(),
mimeType: 'text/json',
text: JSON.stringify(result.body, null, 2)
text: JSON.stringify(result, null, 2)
}]
}
}

View File

@@ -4,27 +4,13 @@ export default defineMcpResource({
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)
})
}
const result = await $fetch('/api/uses')
return {
contents: [{
uri: uri.toString(),
mimeType: 'text/json',
text: JSON.stringify(uses_by_categories, null, 2)
text: JSON.stringify(result, null, 2)
}]
}
}