@enokdev/springdocs-mcp 1.1.1 → 1.2.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +80 -1
- package/build/debug.d.ts +3 -0
- package/build/debug.d.ts.map +1 -0
- package/build/debug.js +292 -0
- package/build/debug.js.map +1 -0
- package/build/index.js +16 -10
- package/build/index.js.map +1 -1
- package/package.json +13 -3
- package/.github/workflows/publish.yml +0 -64
- package/CHANGELOG.md +0 -82
- package/CONTRIBUTING.md +0 -215
- package/EXAMPLES.md +0 -0
- package/EXAMPLES_FR.md +0 -186
- package/INSTALL.md +0 -0
- package/INSTALL_FR.md +0 -123
- package/README_FR.md +0 -219
- package/RELEASE_NOTES_v1.1.0.md +0 -106
- package/claude_desktop_config.json +0 -8
- package/docs/index.html +0 -147
- package/guid.md +0 -92
- package/publish.sh +0 -130
- package/src/index.ts +0 -287
- package/src/services/springboot-docs.ts +0 -615
- package/src/tools/index.ts +0 -144
- package/test.sh +0 -64
- package/tsconfig.json +0 -24
package/publish.sh
DELETED
|
@@ -1,130 +0,0 @@
|
|
|
1
|
-
#!/bin/bash
|
|
2
|
-
|
|
3
|
-
# Script de publication automatique pour @enokdev/springdocs-mcp
|
|
4
|
-
# Auteur: EnokDev (https://github.com/tky0065)
|
|
5
|
-
|
|
6
|
-
set -e
|
|
7
|
-
|
|
8
|
-
echo "🌱 Publication de Spring Documentation MCP Server"
|
|
9
|
-
echo "=================================================="
|
|
10
|
-
echo ""
|
|
11
|
-
|
|
12
|
-
# Vérifications préliminaires
|
|
13
|
-
echo "🔍 Vérifications pré-publication..."
|
|
14
|
-
|
|
15
|
-
# Vérifier que nous sommes connectés à npm
|
|
16
|
-
NPM_USER=$(npm whoami 2>/dev/null || echo "")
|
|
17
|
-
if [ "$NPM_USER" != "enokdev" ]; then
|
|
18
|
-
echo "❌ Erreur: Vous devez être connecté à npm en tant qu'enokdev"
|
|
19
|
-
echo "Exécutez: npm login"
|
|
20
|
-
exit 1
|
|
21
|
-
fi
|
|
22
|
-
|
|
23
|
-
echo "✅ Connecté à npm en tant que: $NPM_USER"
|
|
24
|
-
|
|
25
|
-
# Vérifier que le build fonctionne
|
|
26
|
-
echo "🔨 Compilation du projet..."
|
|
27
|
-
npm run build
|
|
28
|
-
|
|
29
|
-
# Exécuter les tests
|
|
30
|
-
echo "🧪 Exécution des tests..."
|
|
31
|
-
npm test
|
|
32
|
-
|
|
33
|
-
# Vérifier la configuration Git
|
|
34
|
-
if ! git remote get-url origin | grep -q "tky0065/springdocs-mcp"; then
|
|
35
|
-
echo "⚠️ Attention: L'origin Git ne semble pas pointer vers tky0065/springdocs-mcp"
|
|
36
|
-
echo "Origin actuel: $(git remote get-url origin)"
|
|
37
|
-
read -p "Continuer quand même? (y/N): " -n 1 -r
|
|
38
|
-
echo
|
|
39
|
-
if [[ ! $REPLY =~ ^[Yy]$ ]]; then
|
|
40
|
-
exit 1
|
|
41
|
-
fi
|
|
42
|
-
fi
|
|
43
|
-
|
|
44
|
-
# Afficher la version actuelle
|
|
45
|
-
CURRENT_VERSION=$(node -p "require('./package.json').version")
|
|
46
|
-
echo "📦 Version actuelle: $CURRENT_VERSION"
|
|
47
|
-
|
|
48
|
-
# Demander le type de mise à jour
|
|
49
|
-
echo ""
|
|
50
|
-
echo "Type de mise à jour:"
|
|
51
|
-
echo "1) patch (1.1.0 -> 1.1.1) - Corrections de bugs"
|
|
52
|
-
echo "2) minor (1.1.0 -> 1.2.0) - Nouvelles fonctionnalités"
|
|
53
|
-
echo "3) major (1.1.0 -> 2.0.0) - Changements incompatibles"
|
|
54
|
-
echo "4) Garder la version actuelle"
|
|
55
|
-
|
|
56
|
-
read -p "Votre choix (1-4): " -n 1 -r
|
|
57
|
-
echo
|
|
58
|
-
|
|
59
|
-
case $REPLY in
|
|
60
|
-
1) VERSION_TYPE="patch" ;;
|
|
61
|
-
2) VERSION_TYPE="minor" ;;
|
|
62
|
-
3) VERSION_TYPE="major" ;;
|
|
63
|
-
4) VERSION_TYPE="" ;;
|
|
64
|
-
*) echo "❌ Choix invalide"; exit 1 ;;
|
|
65
|
-
esac
|
|
66
|
-
|
|
67
|
-
# Mise à jour de version si nécessaire
|
|
68
|
-
if [ ! -z "$VERSION_TYPE" ]; then
|
|
69
|
-
echo "📝 Mise à jour de version ($VERSION_TYPE)..."
|
|
70
|
-
npm version $VERSION_TYPE --no-git-tag-version
|
|
71
|
-
NEW_VERSION=$(node -p "require('./package.json').version")
|
|
72
|
-
echo "✅ Nouvelle version: $NEW_VERSION"
|
|
73
|
-
else
|
|
74
|
-
NEW_VERSION=$CURRENT_VERSION
|
|
75
|
-
echo "📌 Conservation de la version: $NEW_VERSION"
|
|
76
|
-
fi
|
|
77
|
-
|
|
78
|
-
# Test final du package
|
|
79
|
-
echo "🔍 Test final du package..."
|
|
80
|
-
npm pack --dry-run > /dev/null
|
|
81
|
-
|
|
82
|
-
# Confirmation finale
|
|
83
|
-
echo ""
|
|
84
|
-
echo "🚀 Prêt pour la publication:"
|
|
85
|
-
echo " Package: @enokdev/springdocs-mcp@$NEW_VERSION"
|
|
86
|
-
echo " Registry: https://www.npmjs.com/package/@enokdev/springdocs-mcp"
|
|
87
|
-
echo " Repository: https://github.com/tky0065/springdocs-mcp"
|
|
88
|
-
echo ""
|
|
89
|
-
|
|
90
|
-
read -p "Confirmer la publication? (y/N): " -n 1 -r
|
|
91
|
-
echo
|
|
92
|
-
if [[ ! $REPLY =~ ^[Yy]$ ]]; then
|
|
93
|
-
echo "❌ Publication annulée"
|
|
94
|
-
exit 1
|
|
95
|
-
fi
|
|
96
|
-
|
|
97
|
-
# Git commit et push
|
|
98
|
-
if [ ! -z "$VERSION_TYPE" ]; then
|
|
99
|
-
echo "📤 Envoi vers GitHub..."
|
|
100
|
-
git add .
|
|
101
|
-
git commit -m "Release v$NEW_VERSION"
|
|
102
|
-
git tag "v$NEW_VERSION"
|
|
103
|
-
git push origin main --tags
|
|
104
|
-
echo "✅ Code envoyé vers GitHub avec tag v$NEW_VERSION"
|
|
105
|
-
fi
|
|
106
|
-
|
|
107
|
-
# Publication npm
|
|
108
|
-
echo "📦 Publication sur npm..."
|
|
109
|
-
npm publish --access public
|
|
110
|
-
|
|
111
|
-
echo ""
|
|
112
|
-
echo "🎉 Publication réussie!"
|
|
113
|
-
echo ""
|
|
114
|
-
echo "📋 Informations de publication:"
|
|
115
|
-
echo " 📦 Package: https://www.npmjs.com/package/@enokdev/springdocs-mcp"
|
|
116
|
-
echo " 🐙 GitHub: https://github.com/tky0065/springdocs-mcp"
|
|
117
|
-
echo " 📊 Stats: https://npm-stat.com/charts.html?package=@enokdev/springdocs-mcp"
|
|
118
|
-
echo ""
|
|
119
|
-
echo "📥 Installation pour les utilisateurs:"
|
|
120
|
-
echo " npm install -g @enokdev/springdocs-mcp"
|
|
121
|
-
echo ""
|
|
122
|
-
echo "🔧 Configuration Claude Desktop:"
|
|
123
|
-
echo ' {"mcpServers": {"spring-docs": {"command": "springdocs-mcp"}}}'
|
|
124
|
-
echo ""
|
|
125
|
-
echo "🌟 N'oubliez pas de:"
|
|
126
|
-
echo " • Annoncer sur les réseaux sociaux"
|
|
127
|
-
echo " • Mettre à jour la documentation si nécessaire"
|
|
128
|
-
echo " • Répondre aux issues GitHub"
|
|
129
|
-
echo ""
|
|
130
|
-
echo "Merci d'avoir publié un outil utile pour la communauté Spring! 🌱"
|
package/src/index.ts
DELETED
|
@@ -1,287 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
|
|
3
|
-
import { Server } from "@modelcontextprotocol/sdk/server/index.js";
|
|
4
|
-
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
|
|
5
|
-
import { CallToolRequestSchema, ListToolsRequestSchema, CallToolRequest, ListToolsRequest } from "@modelcontextprotocol/sdk/types.js";
|
|
6
|
-
import { SpringBootDocsService } from "./services/springboot-docs.js";
|
|
7
|
-
import { ToolDefinitions } from "./tools/index.js";
|
|
8
|
-
|
|
9
|
-
/**
|
|
10
|
-
* Serveur MCP pour accéder à la documentation Spring Boot
|
|
11
|
-
*/
|
|
12
|
-
class SpringBootMCPServer {
|
|
13
|
-
private server: Server;
|
|
14
|
-
private docsService: SpringBootDocsService;
|
|
15
|
-
|
|
16
|
-
constructor() {
|
|
17
|
-
this.server = new Server(
|
|
18
|
-
{
|
|
19
|
-
name: "springboot-mcp-server",
|
|
20
|
-
version: "1.1.0",
|
|
21
|
-
},
|
|
22
|
-
{
|
|
23
|
-
capabilities: {
|
|
24
|
-
tools: {},
|
|
25
|
-
},
|
|
26
|
-
}
|
|
27
|
-
);
|
|
28
|
-
|
|
29
|
-
this.docsService = new SpringBootDocsService();
|
|
30
|
-
this.setupToolHandlers();
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
private setupToolHandlers() {
|
|
34
|
-
// Gestionnaire pour lister les outils disponibles
|
|
35
|
-
this.server.setRequestHandler(ListToolsRequestSchema, async (request: ListToolsRequest) => {
|
|
36
|
-
return {
|
|
37
|
-
tools: ToolDefinitions.getToolList(),
|
|
38
|
-
};
|
|
39
|
-
});
|
|
40
|
-
|
|
41
|
-
// Gestionnaire pour exécuter un outil
|
|
42
|
-
this.server.setRequestHandler(CallToolRequestSchema, async (request: CallToolRequest) => {
|
|
43
|
-
const { name, arguments: args } = request.params;
|
|
44
|
-
|
|
45
|
-
try {
|
|
46
|
-
switch (name) {
|
|
47
|
-
case "search_spring_docs":
|
|
48
|
-
return await this.handleSearchDocs(args);
|
|
49
|
-
|
|
50
|
-
case "search_spring_projects":
|
|
51
|
-
return await this.handleSearchProjects(args);
|
|
52
|
-
|
|
53
|
-
case "get_spring_project":
|
|
54
|
-
return await this.handleGetProject(args);
|
|
55
|
-
|
|
56
|
-
case "get_all_spring_guides":
|
|
57
|
-
return await this.handleGetAllGuides(args);
|
|
58
|
-
|
|
59
|
-
case "get_spring_guide":
|
|
60
|
-
return await this.handleGetGuide(args);
|
|
61
|
-
|
|
62
|
-
case "get_spring_reference":
|
|
63
|
-
return await this.handleGetReference(args);
|
|
64
|
-
|
|
65
|
-
case "search_spring_concepts":
|
|
66
|
-
return await this.handleSearchConcepts(args);
|
|
67
|
-
|
|
68
|
-
default:
|
|
69
|
-
throw new Error(`Outil inconnu: ${name}`);
|
|
70
|
-
}
|
|
71
|
-
} catch (error) {
|
|
72
|
-
const errorMessage = error instanceof Error ? error.message : "Erreur inconnue";
|
|
73
|
-
return {
|
|
74
|
-
content: [
|
|
75
|
-
{
|
|
76
|
-
type: "text",
|
|
77
|
-
text: `Erreur lors de l'exécution de l'outil ${name}: ${errorMessage}`,
|
|
78
|
-
},
|
|
79
|
-
],
|
|
80
|
-
isError: true,
|
|
81
|
-
};
|
|
82
|
-
}
|
|
83
|
-
});
|
|
84
|
-
}
|
|
85
|
-
|
|
86
|
-
private async handleSearchProjects(args: any) {
|
|
87
|
-
const { query, limit = 10 } = args;
|
|
88
|
-
|
|
89
|
-
if (!query || typeof query !== "string") {
|
|
90
|
-
throw new Error("Le paramètre 'query' est requis et doit être une chaîne de caractères");
|
|
91
|
-
}
|
|
92
|
-
|
|
93
|
-
const results = await this.docsService.searchSpringProjects(query, limit);
|
|
94
|
-
|
|
95
|
-
return {
|
|
96
|
-
content: [
|
|
97
|
-
{
|
|
98
|
-
type: "text",
|
|
99
|
-
text: `Projets Spring trouvés pour "${query}":\n\n${this.formatSearchResults(results)}`,
|
|
100
|
-
},
|
|
101
|
-
],
|
|
102
|
-
};
|
|
103
|
-
}
|
|
104
|
-
|
|
105
|
-
private async handleGetProject(args: any) {
|
|
106
|
-
const { projectName } = args;
|
|
107
|
-
|
|
108
|
-
if (!projectName || typeof projectName !== "string") {
|
|
109
|
-
throw new Error("Le paramètre 'projectName' est requis et doit être une chaîne de caractères");
|
|
110
|
-
}
|
|
111
|
-
|
|
112
|
-
const project = await this.docsService.getSpringProject(projectName);
|
|
113
|
-
|
|
114
|
-
return {
|
|
115
|
-
content: [
|
|
116
|
-
{
|
|
117
|
-
type: "text",
|
|
118
|
-
text: project,
|
|
119
|
-
},
|
|
120
|
-
],
|
|
121
|
-
};
|
|
122
|
-
}
|
|
123
|
-
|
|
124
|
-
private async handleGetAllGuides(args: any) {
|
|
125
|
-
const { category, limit = 20 } = args;
|
|
126
|
-
|
|
127
|
-
const results = await this.docsService.getAllSpringGuides(category, limit);
|
|
128
|
-
|
|
129
|
-
return {
|
|
130
|
-
content: [
|
|
131
|
-
{
|
|
132
|
-
type: "text",
|
|
133
|
-
text: `Guides Spring disponibles${category ? ` dans la catégorie "${category}"` : ""}:\n\n${this.formatSearchResults(results)}`,
|
|
134
|
-
},
|
|
135
|
-
],
|
|
136
|
-
};
|
|
137
|
-
}
|
|
138
|
-
|
|
139
|
-
private async handleSearchDocs(args: any) {
|
|
140
|
-
const { query, docType = "all", limit = 10 } = args;
|
|
141
|
-
|
|
142
|
-
if (!query || typeof query !== "string") {
|
|
143
|
-
throw new Error("Le paramètre 'query' est requis et doit être une chaîne de caractères");
|
|
144
|
-
}
|
|
145
|
-
|
|
146
|
-
const results = await this.docsService.searchDocumentation(query, docType, limit);
|
|
147
|
-
|
|
148
|
-
return {
|
|
149
|
-
content: [
|
|
150
|
-
{
|
|
151
|
-
type: "text",
|
|
152
|
-
text: `Résultats de recherche pour "${query}":\n\n${this.formatSearchResults(results)}`,
|
|
153
|
-
},
|
|
154
|
-
],
|
|
155
|
-
};
|
|
156
|
-
}
|
|
157
|
-
|
|
158
|
-
private async handleGetGuide(args: any) {
|
|
159
|
-
const { guideId } = args;
|
|
160
|
-
|
|
161
|
-
if (!guideId || typeof guideId !== "string") {
|
|
162
|
-
throw new Error("Le paramètre 'guideId' est requis et doit être une chaîne de caractères");
|
|
163
|
-
}
|
|
164
|
-
|
|
165
|
-
const guide = await this.docsService.getGuide(guideId);
|
|
166
|
-
|
|
167
|
-
return {
|
|
168
|
-
content: [
|
|
169
|
-
{
|
|
170
|
-
type: "text",
|
|
171
|
-
text: guide,
|
|
172
|
-
},
|
|
173
|
-
],
|
|
174
|
-
};
|
|
175
|
-
}
|
|
176
|
-
|
|
177
|
-
private async handleGetReference(args: any) {
|
|
178
|
-
const { section, subsection } = args;
|
|
179
|
-
|
|
180
|
-
if (!section || typeof section !== "string") {
|
|
181
|
-
throw new Error("Le paramètre 'section' est requis et doit être une chaîne de caractères");
|
|
182
|
-
}
|
|
183
|
-
|
|
184
|
-
const reference = await this.docsService.getReference(section, subsection);
|
|
185
|
-
|
|
186
|
-
return {
|
|
187
|
-
content: [
|
|
188
|
-
{
|
|
189
|
-
type: "text",
|
|
190
|
-
text: reference,
|
|
191
|
-
},
|
|
192
|
-
],
|
|
193
|
-
};
|
|
194
|
-
}
|
|
195
|
-
|
|
196
|
-
private async handleSearchConcepts(args: any) {
|
|
197
|
-
const { concept, category } = args;
|
|
198
|
-
|
|
199
|
-
if (!concept || typeof concept !== "string") {
|
|
200
|
-
throw new Error("Le paramètre 'concept' est requis et doit être une chaîne de caractères");
|
|
201
|
-
}
|
|
202
|
-
|
|
203
|
-
const results = await this.docsService.searchConcepts(concept, category);
|
|
204
|
-
|
|
205
|
-
return {
|
|
206
|
-
content: [
|
|
207
|
-
{
|
|
208
|
-
type: "text",
|
|
209
|
-
text: this.formatConceptResults(results),
|
|
210
|
-
},
|
|
211
|
-
],
|
|
212
|
-
};
|
|
213
|
-
}
|
|
214
|
-
|
|
215
|
-
private formatSearchResults(results: any[]): string {
|
|
216
|
-
if (results.length === 0) {
|
|
217
|
-
return "Aucun résultat trouvé.";
|
|
218
|
-
}
|
|
219
|
-
|
|
220
|
-
return results
|
|
221
|
-
.map((result, index) => {
|
|
222
|
-
return `${index + 1}. **${result.title}**
|
|
223
|
-
Type: ${result.type}
|
|
224
|
-
URL: ${result.url}
|
|
225
|
-
Description: ${result.description || "Aucune description disponible"}
|
|
226
|
-
|
|
227
|
-
`;
|
|
228
|
-
})
|
|
229
|
-
.join("\n");
|
|
230
|
-
}
|
|
231
|
-
|
|
232
|
-
private formatConceptResults(results: any): string {
|
|
233
|
-
if (!results || Object.keys(results).length === 0) {
|
|
234
|
-
return "Aucun concept trouvé.";
|
|
235
|
-
}
|
|
236
|
-
|
|
237
|
-
let formatted = `# Concepts Spring Boot\n\n`;
|
|
238
|
-
|
|
239
|
-
for (const [category, concepts] of Object.entries(results)) {
|
|
240
|
-
formatted += `## ${category}\n\n`;
|
|
241
|
-
|
|
242
|
-
if (Array.isArray(concepts)) {
|
|
243
|
-
concepts.forEach((concept: any) => {
|
|
244
|
-
formatted += `- **${concept.name}**: ${concept.description}\n`;
|
|
245
|
-
if (concept.examples && concept.examples.length > 0) {
|
|
246
|
-
formatted += ` Exemples: ${concept.examples.join(", ")}\n`;
|
|
247
|
-
}
|
|
248
|
-
});
|
|
249
|
-
}
|
|
250
|
-
|
|
251
|
-
formatted += "\n";
|
|
252
|
-
}
|
|
253
|
-
|
|
254
|
-
return formatted;
|
|
255
|
-
}
|
|
256
|
-
|
|
257
|
-
async run() {
|
|
258
|
-
const transport = new StdioServerTransport();
|
|
259
|
-
await this.server.connect(transport);
|
|
260
|
-
console.error("Serveur MCP Spring Boot démarré sur stdio");
|
|
261
|
-
}
|
|
262
|
-
}
|
|
263
|
-
|
|
264
|
-
// Point d'entrée principal
|
|
265
|
-
async function main() {
|
|
266
|
-
const server = new SpringBootMCPServer();
|
|
267
|
-
await server.run();
|
|
268
|
-
}
|
|
269
|
-
|
|
270
|
-
// Gestion des erreurs
|
|
271
|
-
process.on("SIGINT", async () => {
|
|
272
|
-
console.error("Arrêt du serveur...");
|
|
273
|
-
process.exit(0);
|
|
274
|
-
});
|
|
275
|
-
|
|
276
|
-
process.on("unhandledRejection", (reason: any, promise: Promise<any>) => {
|
|
277
|
-
console.error("Rejet de promesse non géré:", reason);
|
|
278
|
-
process.exit(1);
|
|
279
|
-
});
|
|
280
|
-
|
|
281
|
-
// Démarrage du serveur
|
|
282
|
-
if (import.meta.url === `file://${process.argv[1]}`) {
|
|
283
|
-
main().catch((error) => {
|
|
284
|
-
console.error("Erreur fatale:", error);
|
|
285
|
-
process.exit(1);
|
|
286
|
-
});
|
|
287
|
-
}
|