Skip to main content
Glama
PackageManager.tsx•3.62 kB
import React, { useState, useEffect, useCallback } from 'react'; import { useTool } from '@modelcontextprotocol/sdk/react'; import Spinner from './Spinner.js'; interface PackageManagerProps { addToTerminal: (output: string) => void; } const getCommandOutput = (result: { content: { type: "text"; text: string }[] } | null | undefined): string => { if (result?.content?.[0]?.type === 'text') { return result.content[0].text.split('\nCWD_MARKER:')[0].trim(); } return ''; }; const PackageManager: React.FC<PackageManagerProps> = ({ addToTerminal }) => { const [packageName, setPackageName] = useState(''); const [installedPackages, setInstalledPackages] = useState<string[]>([]); const { call: runCommand, isPending } = useTool('run_bash_command'); const fetchPackages = useCallback(async () => { const result = await runCommand({ command: 'pip list' }); const output = getCommandOutput(result); if (output) { // pip list has a 2-line header, skip it. const lines = output.split('\n').slice(2); setInstalledPackages(lines); } }, [runCommand]); useEffect(() => { fetchPackages(); }, [fetchPackages]); const handleInstall = async () => { if (!packageName.trim()) return; addToTerminal(`Running: pip install ${packageName}...`); const result = await runCommand({ command: `pip install ${packageName}` }); const output = getCommandOutput(result); addToTerminal(output || 'Installation complete.'); setPackageName(''); fetchPackages(); // Refresh the list of installed packages }; return ( <div style={styles.container}> <div style={styles.header}>PACKAGE MANAGER</div> <div style={styles.installSection}> <input type="text" value={packageName} onChange={(e) => setPackageName(e.target.value)} placeholder="e.g., pandas" style={styles.input} /> <button onClick={handleInstall} disabled={isPending} style={styles.button}> {isPending ? <Spinner size={16} /> : 'Install'} </button> </div> <div style={styles.listSection}> <h3 style={styles.listHeader}>Installed Packages (via pip)</h3> {isPending ? <Spinner /> : ( <ul style={styles.packageList}> {installedPackages.map((pkg, i) => ( <li key={i} style={styles.packageItem}>{pkg}</li> ))} </ul> )} </div> </div> ); }; const styles: { [key: string]: React.CSSProperties } = { container: { display: 'flex', flexDirection: 'column', height: '100%', color: 'var(--text-primary)' }, header: { padding: '10px', fontWeight: 'bold', borderBottom: '1px solid var(--border-color)', flexShrink: 0 }, installSection: { padding: '10px', display: 'flex', gap: '10px', borderBottom: '1px solid var(--border-color)', flexShrink: 0 }, input: { flex: 1, padding: '5px', backgroundColor: 'var(--background-tertiary)', border: '1px solid var(--border-color)', color: 'var(--text-primary)', borderRadius: '3px' }, button: { padding: '5px 10px', backgroundColor: 'var(--accent-primary)', color: 'white', border: 'none', borderRadius: '3px', cursor: 'pointer', minWidth: '70px', display: 'flex', justifyContent: 'center', alignItems: 'center' }, listSection: { flex: 1, padding: '10px', overflowY: 'auto' }, listHeader: { marginTop: 0, fontSize: '14px', color: 'var(--text-secondary)' }, packageList: { listStyle: 'none', padding: 0, margin: 0 }, packageItem: { padding: '4px 0', fontSize: '13px', fontFamily: 'monospace' }, }; export default PackageManager;

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/pythondev-pro/egw_writings_mcp_server'

If you have feedback or need assistance with the MCP directory API, please join our Discord server