Skip to content

Commit f0b706e

Browse files
author
Lasim
committed
feat(all): add README content management to MCP server forms
1 parent 5de8134 commit f0b706e

File tree

7 files changed

+154
-4
lines changed

7 files changed

+154
-4
lines changed

services/backend/src/routes/mcp/servers/schemas.ts

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1023,10 +1023,14 @@ export const UPDATE_GLOBAL_SERVER_REQUEST_SCHEMA = { type: 'object',
10231023
repository_subfolder: SERVER_FIELDS.repository_subfolder,
10241024
git_branch: SERVER_FIELDS.git_branch,
10251025
website_url: SERVER_FIELDS.website_url,
1026-
github_account_id: {
1026+
github_account_id: {
10271027
type: 'string',
10281028
description: 'GitHub Account ID (owner.id from GitHub API)'
10291029
},
1030+
github_readme_base64: {
1031+
type: 'string',
1032+
description: 'Base64 encoded README content'
1033+
},
10301034
language: SERVER_FIELDS.language,
10311035
runtime: SERVER_FIELDS.runtime,
10321036
transport_type: SERVER_FIELDS.transport_type,

services/backend/src/routes/mcp/servers/update-global.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ interface UpdateGlobalServerRequest {
2727
git_branch?: string;
2828
website_url?: string;
2929
github_account_id?: string;
30+
github_readme_base64?: string;
3031
language?: string;
3132
runtime?: string;
3233
transport_type?: 'stdio' | 'http' | 'sse';

services/frontend/src/components/admin/mcp-catalog/McpServerAddFormWizard.vue

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -214,6 +214,9 @@ const compatibleFormData = computed((): McpServerFormData => ({
214214
},
215215
configuration_schema: formData.value.configuration_schema,
216216
repository_setup: formData.value.repository,
217+
readme: {
218+
github_readme_base64: ''
219+
},
217220
review: {}
218221
}))
219222

services/frontend/src/components/admin/mcp-catalog/McpServerEditFormWizard.vue

Lines changed: 25 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,14 +17,15 @@ import { useI18n } from 'vue-i18n'
1717
import { Button } from '@/components/ui/button'
1818
import { Alert, AlertDescription } from '@/components/ui/alert'
1919
import { ProgressBars } from '@/components/ui/progress-bars'
20-
import { FileText, GitBranch, Code, Settings, CheckCircle } from 'lucide-vue-next'
20+
import { FileText, GitBranch, Code, Settings, CheckCircle, BookOpen } from 'lucide-vue-next'
2121
import { McpCatalogService } from '@/services/mcpCatalogService'
2222
import { useEventBus } from '@/composables/useEventBus'
2323
import ContentWrapper from '@/components/ContentWrapper.vue'
2424
import BasicInfoStepEdit from '@/components/admin/mcp-catalog/steps/BasicInfoStepEdit.vue'
2525
import TechnicalStep from '@/components/admin/mcp-catalog/TechnicalStep.vue'
2626
import ConfigurationSchemaStepEdit from '@/components/admin/mcp-catalog/steps/ConfigurationSchemaStepEdit.vue'
2727
import RepositoryStep from '@/components/admin/mcp-catalog/RepositoryStep.vue'
28+
import ReadmeStep from '@/components/admin/mcp-catalog/ReadmeStep.vue'
2829
import ReviewStep from '@/components/admin/mcp-catalog/ReviewStep.vue'
2930
import type {
3031
McpServerFormData,
@@ -88,6 +89,12 @@ const steps = [
8889
icon: Settings,
8990
component: ConfigurationSchemaStepEdit
9091
},
92+
{
93+
key: 'readme' as const,
94+
label: 'README',
95+
icon: BookOpen,
96+
component: ReadmeStep
97+
},
9198
{
9299
key: 'review' as const,
93100
label: t('mcpCatalog.form.steps.review'),
@@ -273,6 +280,19 @@ const initializeStorageWithData = (data: McpServerFormData) => {
273280
}
274281
eventBus.setState('edit_claude_config', JSON.stringify(claudeConfig, null, 2))
275282
}
283+
284+
// Initialize README data - decode base64 to markdown for editing
285+
if (data.readme && data.readme.github_readme_base64) {
286+
try {
287+
const readmeMarkdown = atob(data.readme.github_readme_base64)
288+
eventBus.setState('edit_readme_data', { readme_markdown: readmeMarkdown })
289+
} catch (e) {
290+
console.error('Failed to decode README base64:', e)
291+
eventBus.setState('edit_readme_data', { readme_markdown: '' })
292+
}
293+
} else {
294+
eventBus.setState('edit_readme_data', { readme_markdown: '' })
295+
}
276296
}
277297
278298
// Form data with proper initialization
@@ -313,6 +333,9 @@ const formData = ref<McpServerFormData>({
313333
git_branch: '',
314334
auto_populated: false
315335
},
336+
readme: {
337+
github_readme_base64: ''
338+
},
316339
review: {}
317340
})
318341
@@ -329,6 +352,7 @@ watch(
329352
technical: { ...formData.value.technical, ...newInitialData.technical },
330353
configuration_schema: newInitialData.configuration_schema ? newInitialData.configuration_schema : formData.value.configuration_schema,
331354
repository_setup: { ...formData.value.repository_setup, ...newInitialData.repository_setup },
355+
readme: { ...formData.value.readme, ...newInitialData.readme },
332356
review: { ...formData.value.review, ...newInitialData.review }
333357
}
334358
Lines changed: 89 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,89 @@
1+
<script setup lang="ts">
2+
import { ref, watch, onMounted } from 'vue'
3+
import { Label } from '@/components/ui/label'
4+
import { Textarea } from '@/components/ui/textarea'
5+
import { useEventBus } from '@/composables/useEventBus'
6+
import type { McpServerFormData } from '../../../views/admin/mcp-server-catalog/types'
7+
8+
interface Props {
9+
modelValue: McpServerFormData['readme']
10+
formData: McpServerFormData
11+
}
12+
13+
interface Emits {
14+
(e: 'update:modelValue', value: McpServerFormData['readme']): void
15+
}
16+
17+
const props = defineProps<Props>()
18+
const emit = defineEmits<Emits>()
19+
20+
const eventBus = useEventBus()
21+
22+
// Storage key for this step
23+
const STORAGE_KEY = 'edit_readme_data'
24+
25+
// Form state - store as plain markdown text
26+
const readmeMarkdown = ref('')
27+
28+
// Load data from storage on mount
29+
const loadFromStorage = () => {
30+
const stored = eventBus.getState<{ readme_markdown: string }>(STORAGE_KEY)
31+
if (stored) {
32+
readmeMarkdown.value = stored.readme_markdown || ''
33+
} else if (props.modelValue && props.modelValue.github_readme_base64) {
34+
// Decode base64 to markdown for editing
35+
try {
36+
readmeMarkdown.value = atob(props.modelValue.github_readme_base64)
37+
} catch {
38+
readmeMarkdown.value = ''
39+
}
40+
}
41+
}
42+
43+
// Save data to storage
44+
const saveToStorage = () => {
45+
const data = {
46+
readme_markdown: readmeMarkdown.value
47+
}
48+
eventBus.setState(STORAGE_KEY, data)
49+
// Note: We'll convert to base64 only on final submit
50+
emit('update:modelValue', { github_readme_base64: '' })
51+
}
52+
53+
// Watch for changes and auto-save to storage
54+
watch([readmeMarkdown], () => {
55+
saveToStorage()
56+
})
57+
58+
// Initialize on mount
59+
onMounted(() => {
60+
loadFromStorage()
61+
})
62+
</script>
63+
64+
<template>
65+
<div class="space-y-6">
66+
<div>
67+
<h2 class="text-2xl font-semibold mb-2">README Content</h2>
68+
<p class="text-muted-foreground">
69+
Enter the README content in Markdown format
70+
</p>
71+
</div>
72+
73+
<div class="space-y-4">
74+
<!-- README Input -->
75+
<div class="space-y-2">
76+
<Label for="readme-content">README Content (Markdown)</Label>
77+
<Textarea
78+
id="readme-content"
79+
v-model="readmeMarkdown"
80+
placeholder="# My MCP Server&#10;&#10;Description of the server...&#10;&#10;## Features&#10;&#10;- Feature 1&#10;- Feature 2"
81+
class="min-h-[400px] font-mono text-sm"
82+
/>
83+
<p class="text-sm text-muted-foreground">
84+
Enter your README content in Markdown format. It will be automatically converted to base64 when you submit.
85+
</p>
86+
</div>
87+
</div>
88+
</div>
89+
</template>

services/frontend/src/views/admin/mcp-server-catalog/edit/[id].vue

Lines changed: 25 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -47,9 +47,11 @@ const clearEditStorage = () => {
4747
const editStorageKeys = [
4848
'edit_basic_data',
4949
'edit_repository_data',
50+
'edit_repository_setup_data',
5051
'edit_technical_data',
5152
'edit_configuration_schema',
5253
'edit_claude_config',
54+
'edit_readme_data',
5355
'technical_extracted_env_vars_edit',
5456
'mcp_edit_drafts'
5557
]
@@ -80,8 +82,18 @@ const loadServerData = async () => {
8082
8183
serverData.value = server
8284
85+
// Fetch README data separately using dedicated endpoint
86+
let readmeBase64 = ''
87+
try {
88+
const readmeResponse = await McpCatalogService.getServerReadme(serverId)
89+
readmeBase64 = readmeResponse || ''
90+
} catch (readmeError) {
91+
console.warn('Failed to fetch README:', readmeError)
92+
// Continue even if README fetch fails
93+
}
94+
8395
// Convert server data to form data format
84-
initialFormData.value = convertServerToFormData(server)
96+
initialFormData.value = convertServerToFormData(server, readmeBase64)
8597
8698
} catch (error) {
8799
loadError.value = error instanceof Error ? error.message : 'Failed to load server data'
@@ -110,7 +122,7 @@ const parseJsonField = (fieldValue: any, defaultValue: any) => {
110122
}
111123
112124
// Convert server data to form data format
113-
const convertServerToFormData = (server: McpServer): Partial<McpServerFormData> => {
125+
const convertServerToFormData = (server: McpServer, readmeBase64: string = ''): Partial<McpServerFormData> => {
114126
// Parse tags with proper handling
115127
const parsedTags = parseJsonField(server.tags, [])
116128
@@ -181,6 +193,9 @@ const convertServerToFormData = (server: McpServer): Partial<McpServerFormData>
181193
git_branch: server.git_branch || '',
182194
auto_populated: false
183195
},
196+
readme: {
197+
github_readme_base64: readmeBase64
198+
},
184199
review: {}
185200
}
186201
}
@@ -210,6 +225,11 @@ const handleSubmit = async (formData: McpServerFormData) => {
210225
git_branch: repositorySetupData?.git_branch !== undefined ? repositorySetupData.git_branch : formData.repository.git_branch
211226
}
212227
228+
// Get README markdown from storage and convert to base64
229+
const readmeData = eventBus.getState<{ readme_markdown: string }>('edit_readme_data')
230+
const readmeMarkdown = readmeData?.readme_markdown || ''
231+
const readmeBase64 = readmeMarkdown ? btoa(readmeMarkdown) : ''
232+
213233
// CRITICAL FIX: Synchronize environment variables from installation_methods to team_env_schema
214234
let finalConfigurationSchema = { ...formData.configuration_schema }
215235
@@ -278,6 +298,9 @@ const handleSubmit = async (formData: McpServerFormData) => {
278298
git_branch: finalRepositoryData.git_branch ? finalRepositoryData.git_branch : null,
279299
website_url: formData.basic.website_url || undefined,
280300
301+
// README content
302+
github_readme_base64: readmeBase64 || undefined,
303+
281304
// Technical
282305
language: formData.technical.language,
283306
runtime: formData.technical.runtime,

services/frontend/src/views/admin/mcp-server-catalog/types.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -262,6 +262,7 @@ export interface UpdateMcpServerRequest {
262262
description?: string
263263
long_description?: string
264264
github_account_id?: string
265+
github_readme_base64?: string
265266
github_stars?: number
266267
// Repository platform fields
267268
repository_url?: string
@@ -377,12 +378,17 @@ export interface ConfigurationSchemaFormData {
377378
user_url_query_params_schema?: UserUrlQueryParamsSchema[]
378379
}
379380

381+
export interface ReadmeFormData {
382+
github_readme_base64: string
383+
}
384+
380385
export interface McpServerFormData {
381386
basic: BasicInfoFormData
382387
repository: RepositoryFormData
383388
technical: TechnicalFormData
384389
configuration_schema: ConfigurationSchemaFormData
385390
repository_setup: RepositorySetupFormData
391+
readme: ReadmeFormData
386392
review: ReviewFormData
387393
}
388394

0 commit comments

Comments
 (0)