Skip to content

Feat/MCP #496

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 6 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 13 additions & 0 deletions .changeset/sweet-carrots-walk.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
---
'@srcbook/api': patch
'srcbook': patch
---

Add Model Context Protocol (MCP) integration to enhance AI capabilities. This update includes:

- MCP client implementation for connecting to MCP servers
- Tool discovery and execution functionality
- Integration with app generation pipeline
- Documentation in README.md

MCP enables AI models to access external tools and data sources, significantly expanding the capabilities of AI-generated applications.
9 changes: 8 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -45,4 +45,11 @@ srcbook/lib/**/*
# Docs folder
docs/

vite.config.ts.timestamp-*.mjs
vite.config.ts.timestamp-*.mjs

# Roo Code
.roomodes

# MCP config
packages/api/srcbook_mcp_config.json
MCPClientDevGuide.md
31 changes: 30 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
<a href="https://srcbook.com">Online app builder</a> ·
<a href="https://discord.gg/shDEGBSe2d">Discord</a> ·
<a href="https://www.youtube.com/@srcbook">Youtube</a> ·
<a href="https://hub.srcbook.com">Hub</a>
<a href="https://hub.srcbook.com">Hub</a>
</p>

## Srcbook
Expand All @@ -33,6 +33,7 @@ Srcbook is open-source (apache2) and runs locally on your machine. You'll need t
- Create, edit and run web apps
- Use AI to generate the boilerplate, modify the code, and fix things
- Edit the app with a hot-reloading web preview
- MCP (Model Context Protocol) integration for enhanced AI capabilities

<picture>
<source media="(prefers-color-scheme: dark)" srcset="https://i.imgur.com/lLJPZOs.png">
Expand Down Expand Up @@ -137,6 +138,34 @@ In order to improve Srcbook, we collect some behavioral analytics. We don't coll

If you want to disable tracking, you can run Srcbook with `SRCBOOK_DISABLE_ANALYTICS=true` set in the environment.

## MCP Integration

Srcbook now includes support for the Model Context Protocol (MCP), enabling AI models to access external tools and data sources. This integration enhances the capabilities of AI-generated applications by allowing them to:

- Access external data sources and APIs
- Perform web searches and retrieve information
- Execute specialized tools during app generation

MCP servers can be configured in the `packages/api/srcbook_mcp_config.json` file. The MCP client automatically discovers and makes available all tools provided by configured MCP servers.

### Configuring MCP Servers

To add an MCP server, update the configuration file with the server details:

```json
{
"mcpServers": {
"server-id": {
"command": "command-to-run-server",
"args": ["arg1", "arg2"],
"env": {
"API_KEY": "your-api-key"
}
}
}
}
```

## Contributing

For development instructions, see [CONTRIBUTING.md](https://github.com/srcbookdev/srcbook/blob/main/CONTRIBUTING.md).
47 changes: 43 additions & 4 deletions packages/api/ai/generate.mts
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import { PROMPTS_DIR } from '../constants.mjs';
import { encode, decodeCells } from '../srcmd.mjs';
import { buildProjectXml, type FileContent } from '../ai/app-parser.mjs';
import { logAppGeneration } from './logger.mjs';
import { formatMCPToolsForAI } from './mcp-tools.mjs';

const makeGenerateSrcbookSystemPrompt = () => {
return readFileSync(Path.join(PROMPTS_DIR, 'srcbook-generator.txt'), 'utf-8');
Expand All @@ -33,25 +34,63 @@ const makeAppEditorSystemPrompt = () => {
return readFileSync(Path.join(PROMPTS_DIR, 'app-editor.txt'), 'utf-8');
};

const makeAppEditorUserPrompt = (projectId: string, files: FileContent[], query: string) => {
const makeAppEditorUserPrompt = async (projectId: string, files: FileContent[], query: string) => {
const projectXml = buildProjectXml(files, projectId);
const userRequestXml = `<userRequest>${query}</userRequest>`;

// Get MCP tools if available
let mcpToolsXml = '';
try {
const mcpTools = await formatMCPToolsForAI();
if (
mcpTools &&
mcpTools !== 'No MCP tools are available.' &&
mcpTools !== 'Error retrieving MCP tools.'
) {
mcpToolsXml = `<mcpTools>
${mcpTools}
</mcpTools>`;
}
} catch (error) {
console.error('Error getting MCP tools for app editor:', error);
}

return `Following below are the project XML and the user request.

${projectXml}

${userRequestXml}
${mcpToolsXml ? '\n\n' + mcpToolsXml : ''}
`.trim();
};

const makeAppCreateUserPrompt = (projectId: string, files: FileContent[], query: string) => {
const makeAppCreateUserPrompt = async (projectId: string, files: FileContent[], query: string) => {
const projectXml = buildProjectXml(files, projectId);
const userRequestXml = `<userRequest>${query}</userRequest>`;

// Get MCP tools if available
let mcpToolsXml = '';
try {
const mcpTools = await formatMCPToolsForAI();
if (
mcpTools &&
mcpTools !== 'No MCP tools are available.' &&
mcpTools !== 'Error retrieving MCP tools.'
) {
mcpToolsXml = `<mcpTools>
${mcpTools}
</mcpTools>`;
}
} catch (error) {
console.error('Error getting MCP tools for app creation:', error);
}

return `Following below are the project XML and the user request.

${projectXml}

${userRequestXml}
${mcpToolsXml ? '\n\n' + mcpToolsXml : ''}
`.trim();
};

Expand Down Expand Up @@ -252,7 +291,7 @@ export async function generateApp(
const result = await generateText({
model,
system: makeAppBuilderSystemPrompt(),
prompt: makeAppCreateUserPrompt(projectId, files, query),
prompt: await makeAppCreateUserPrompt(projectId, files, query),
});
return result.text;
}
Expand All @@ -267,7 +306,7 @@ export async function streamEditApp(
const model = await getModel();

const systemPrompt = makeAppEditorSystemPrompt();
const userPrompt = makeAppEditorUserPrompt(projectId, files, query);
const userPrompt = await makeAppEditorUserPrompt(projectId, files, query);

let response = '';

Expand Down
114 changes: 114 additions & 0 deletions packages/api/ai/mcp-tools.mts
Original file line number Diff line number Diff line change
@@ -0,0 +1,114 @@
/**
* MCP Tools Formatter
*
* This module provides functions to format MCP tools for AI consumption.
* It converts MCP tool definitions into a format that can be included in AI prompts.
*/

import { getMCPClientManager, type MCPTool } from '../mcp/client-manager.mjs';

/**
* Format MCP tools for inclusion in AI prompts
*
* @returns A formatted string describing all available MCP tools
*/
export async function formatMCPToolsForAI(): Promise<string> {
try {
// Get the MCP client manager
const clientManager = getMCPClientManager();

// Get all available tools
const tools = await clientManager.getTools();

if (tools.length === 0) {
return 'No MCP tools are available.';
}

// Format the tools as a string
return formatToolsAsString(tools);
} catch (error) {
console.error('Error formatting MCP tools for AI:', error);
return 'Error retrieving MCP tools.';
}
}

/**
* Format a list of MCP tools as a string
*
* @param tools The list of MCP tools to format
* @returns A formatted string describing the tools
*/
function formatToolsAsString(tools: MCPTool[]): string {
// Start with a header
let result = '## Available MCP Tools\n\n';
result += 'You can use the following tools to perform actions:\n\n';

// Add each tool
tools.forEach((tool) => {
// Add tool name and description
result += `### ${tool.name}\n`;
if (tool.annotations?.title) {
result += `**${tool.annotations.title}**\n`;
}
if (tool.description) {
result += `${tool.description}\n`;
}

// Add tool annotations as hints
const hints: string[] = [];
if (tool.annotations?.readOnlyHint) hints.push('Read-only');
if (tool.annotations?.destructiveHint) hints.push('Destructive');
if (tool.annotations?.idempotentHint) hints.push('Idempotent');
if (tool.annotations?.openWorldHint) hints.push('Interacts with external systems');

if (hints.length > 0) {
result += `**Hints:** ${hints.join(', ')}\n`;
}

// Add input schema
result += '\n**Input Schema:**\n';
result += '```json\n';
result += JSON.stringify(tool.inputSchema, null, 2);
result += '\n```\n\n';

// Add server ID
result += `**Server:** ${tool.serverId}\n\n`;

// Add separator between tools
result += '---\n\n';
});

// Add usage instructions
result += `## How to Use These Tools

To use a tool, include a tool call in your response using the following format:

\`\`\`
<tool name="TOOL_NAME" server="SERVER_ID">
{
"param1": "value1",
"param2": "value2"
}
</tool>
\`\`\`

Replace TOOL_NAME with the name of the tool you want to use, SERVER_ID with the server ID, and include the appropriate parameters as specified in the tool's input schema.
`;

return result;
}

/**
* Get the list of MCP tools
*
* @returns The list of available MCP tools
*/
export async function getMCPTools(): Promise<MCPTool[]> {
try {
const clientManager = getMCPClientManager();
return await clientManager.getTools();
} catch (error) {
console.error('Error getting MCP tools:', error);
return [];
}
}
Loading