MCP Protocol Architecture
How Bootspring implements the Model Context Protocol.
Overview#
The Model Context Protocol (MCP) is a standard for AI assistants to interact with external tools and resources. Bootspring implements an MCP server that exposes its functionality to AI clients like Claude.
Protocol Basics#
Communication Flow#
┌─────────────────┐ ┌─────────────────┐
│ AI Client │◄────────────▶│ MCP Server │
│ (Claude, etc.) │ Messages │ (Bootspring) │
└─────────────────┘ └─────────────────┘
Message Types#
| Type | Direction | Purpose |
|---|---|---|
initialize | Client → Server | Establish connection |
tools/list | Client → Server | List available tools |
tools/call | Client → Server | Invoke a tool |
resources/list | Client → Server | List available resources |
resources/read | Client → Server | Read a resource |
Bootspring MCP Server#
Server Implementation#
1// mcp-server/src/server.ts
2
3import { Server } from '@modelcontextprotocol/sdk/server';
4import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio';
5
6export class BootspringMcpServer {
7 private server: Server;
8 private toolRegistry: ToolRegistry;
9 private resourceRegistry: ResourceRegistry;
10
11 constructor() {
12 this.server = new Server({
13 name: 'bootspring',
14 version: '1.0.0',
15 }, {
16 capabilities: {
17 tools: {},
18 resources: {},
19 },
20 });
21
22 this.setupHandlers();
23 }
24
25 private setupHandlers(): void {
26 // List tools
27 this.server.setRequestHandler('tools/list', async () => ({
28 tools: this.toolRegistry.list(),
29 }));
30
31 // Call tool
32 this.server.setRequestHandler('tools/call', async (request) => {
33 const { name, arguments: args } = request.params;
34 return this.toolRegistry.call(name, args);
35 });
36
37 // List resources
38 this.server.setRequestHandler('resources/list', async () => ({
39 resources: this.resourceRegistry.list(),
40 }));
41
42 // Read resource
43 this.server.setRequestHandler('resources/read', async (request) => {
44 const { uri } = request.params;
45 return this.resourceRegistry.read(uri);
46 });
47 }
48
49 async start(): Promise<void> {
50 const transport = new StdioServerTransport();
51 await this.server.connect(transport);
52 }
53}Tool System#
Tool Definition#
1interface McpTool {
2 name: string;
3 description: string;
4 inputSchema: JsonSchema;
5}
6
7interface ToolHandler {
8 (args: Record<string, unknown>): Promise<ToolResult>;
9}Registered Tools#
| Tool | Description |
|---|---|
bootspring_assist | Natural language assistant |
bootspring_context | Get project context |
bootspring_agent | Invoke expert agents |
bootspring_skill | Discover and apply skills |
bootspring_todo | Manage todos |
bootspring_generate | Regenerate context |
bootspring_workflow | Workflow operations |
bootspring_quality | Quality gates |
bootspring_prd | PRD management |
bootspring_loop | Development loops |
bootspring_seed | Seed operations |
bootspring_mvp | MVP generation |
bootspring_memory | Access memory |
bootspring_dashboard | Dashboard control |
bootspring_config | Configuration |
bootspring_analyze | Code analysis |
bootspring_feedback | Send feedback |
bootspring_status | Check status |
bootspring_orchestrator | Orchestrate workflows |
Tool Implementation Example#
1// mcp-server/src/tools/agent.ts
2
3export const agentTool: McpTool = {
4 name: 'bootspring_agent',
5 description: 'Invoke an expert agent for specialized assistance',
6 inputSchema: {
7 type: 'object',
8 properties: {
9 agent: {
10 type: 'string',
11 description: 'Agent name (e.g., frontend-expert)',
12 },
13 prompt: {
14 type: 'string',
15 description: 'Task or question for the agent',
16 },
17 context: {
18 type: 'object',
19 description: 'Additional context',
20 properties: {
21 files: { type: 'array', items: { type: 'string' } },
22 },
23 },
24 },
25 required: ['agent', 'prompt'],
26 },
27};
28
29export async function handleAgentTool(
30 args: { agent: string; prompt: string; context?: object }
31): Promise<ToolResult> {
32 const invoker = new AgentInvoker();
33
34 const result = await invoker.invoke(args.agent, args.prompt, {
35 files: args.context?.files,
36 });
37
38 return {
39 content: [{
40 type: 'text',
41 text: result.response,
42 }],
43 };
44}Resource System#
Resource Definition#
1interface McpResource {
2 uri: string;
3 name: string;
4 description: string;
5 mimeType: string;
6}Registered Resources#
| URI | Description |
|---|---|
project://context | Project context (CLAUDE.md) |
project://config | Bootspring configuration |
project://prd | Product Requirements |
project://todos | Todo list |
Resource Implementation#
1// mcp-server/src/resources/context.ts
2
3export const contextResource: McpResource = {
4 uri: 'project://context',
5 name: 'Project Context',
6 description: 'Generated project context (CLAUDE.md)',
7 mimeType: 'text/markdown',
8};
9
10export async function readContextResource(): Promise<ResourceContent> {
11 const contextPath = await findContextFile();
12
13 if (!contextPath) {
14 return {
15 contents: [{
16 uri: 'project://context',
17 mimeType: 'text/plain',
18 text: 'No context file found. Run `bootspring generate` to create one.',
19 }],
20 };
21 }
22
23 const content = await fs.readFile(contextPath, 'utf-8');
24
25 return {
26 contents: [{
27 uri: 'project://context',
28 mimeType: 'text/markdown',
29 text: content,
30 }],
31 };
32}Transport Layer#
Stdio Transport#
For Claude Desktop integration:
// Start with stdio transport
bootspring mcp start --stdioCommunication via stdin/stdout with JSON-RPC messages.
HTTP Transport#
For web integrations:
// Start with HTTP transport
bootspring mcp start --port=3100RESTful API with WebSocket support for streaming.
Message Format#
JSON-RPC 2.0#
All MCP messages use JSON-RPC 2.0:
1// Request
2{
3 "jsonrpc": "2.0",
4 "id": 1,
5 "method": "tools/call",
6 "params": {
7 "name": "bootspring_agent",
8 "arguments": {
9 "agent": "frontend-expert",
10 "prompt": "Create a button component"
11 }
12 }
13}
14
15// Response
16{
17 "jsonrpc": "2.0",
18 "id": 1,
19 "result": {
20 "content": [{
21 "type": "text",
22 "text": "Here's a button component..."
23 }]
24 }
25}Streaming Responses#
For long operations:
1// Progress notification
2{
3 "jsonrpc": "2.0",
4 "method": "notifications/progress",
5 "params": {
6 "progressToken": "abc123",
7 "progress": 50,
8 "total": 100
9 }
10}Authentication#
Session Authentication#
1// Initialize with auth
2{
3 "method": "initialize",
4 "params": {
5 "clientInfo": {
6 "name": "claude-desktop",
7 "version": "1.0.0"
8 },
9 "capabilities": {}
10 }
11}API Key Validation#
Tools validate API keys for cloud operations:
1async function validateApiKey(args: ToolArgs): Promise<void> {
2 if (requiresAuth(args)) {
3 const apiKey = await getStoredApiKey();
4 if (!apiKey) {
5 throw new AuthenticationRequiredError();
6 }
7 await validateWithApi(apiKey);
8 }
9}Error Handling#
MCP Error Codes#
| Code | Meaning |
|---|---|
| -32700 | Parse error |
| -32600 | Invalid request |
| -32601 | Method not found |
| -32602 | Invalid params |
| -32603 | Internal error |
Bootspring Errors#
| Code | Meaning |
|---|---|
| 1001 | Agent not found |
| 1002 | Skill not found |
| 1003 | Authentication required |
| 1004 | Rate limit exceeded |
| 1005 | Entitlement required |
Client Configuration#
Claude Desktop#
1{
2 "mcpServers": {
3 "bootspring": {
4 "command": "bootspring",
5 "args": ["mcp", "start", "--stdio"],
6 "cwd": "/path/to/project"
7 }
8 }
9}VS Code#
{
"bootspring.mcp.enabled": true,
"bootspring.mcp.port": 3100
}Debugging#
Enable Debug Logging#
DEBUG=mcp:* bootspring mcp start --stdioLog Output#
mcp:server Received: tools/list
mcp:server Responding with 19 tools
mcp:server Received: tools/call bootspring_agent
mcp:tools Invoking agent: frontend-expert
mcp:tools Agent completed in 2340ms
mcp:server Responding with result
Performance#
Connection Pooling#
MCP server maintains connection pools:
const pool = {
maxConnections: 10,
idleTimeout: 30000,
acquireTimeout: 5000,
};Response Caching#
Cacheable responses are stored:
const cacheConfig = {
'project://context': { ttl: 60000 },
'project://config': { ttl: 300000 },
};Security#
Input Validation#
All tool inputs validated against schemas:
1function validateToolInput(tool: McpTool, args: unknown): void {
2 const ajv = new Ajv();
3 const validate = ajv.compile(tool.inputSchema);
4
5 if (!validate(args)) {
6 throw new InvalidParamsError(validate.errors);
7 }
8}Sandboxing#
Tool execution is sandboxed:
- File access limited to project directory
- Network access controlled
- Resource limits enforced
Related#
- MCP Tools - Tool documentation
- MCP Integration - Concepts
- CLI mcp - CLI commands