← Corpus / lost-in-public / exploration
Exploring Model Context Protocol SDK
Tinker with the Model Context Protocol SDK created by Anthropic
- Path
- explorations/Exploring Model Context Protocol SDK.md
- Authors
- Michael Staton
- Augmented with
- Windsurf Cascade with SWE-1
- Tags
- Explorations · Model-Context-Protocols
Model Context Protocol (MCP) Analysis
Core Concept
The Model Context Protocol (MCP) is an open protocol that standardizes how applications provide context to Large Language Models (LLMs). It serves as a universal connector between LLMs and various data sources or tools, similar to how USB-C provides a standardized way to connect devices to peripherals.
Architecture Overview
MCP follows a client-server architecture with the following key components:
flowchart LR
subgraph "Your Computer"
Host["Host with MCP Client\n(e.g., Claude, IDEs, Tools)"]
S1["MCP Server A"]
S2["MCP Server B"]
S3["MCP Server C"]
Host <-->|"MCP Protocol"| S1
Host <-->|"MCP Protocol"| S2
Host <-->|"MCP Protocol"| S3
S1 <--> D1[("Local\nData Source A")]
S2 <--> D2[("Local\nData Source B")]
end
subgraph "Internet"
S3 <-->|"Web APIs"| D3[("Remote\nService C")]
end
Key Components
-
MCP Hosts
- Applications that want to access data through MCP (e.g., Claude Desktop, IDEs, AI tools)
- Maintains connections to one or more MCP servers
-
MCP Clients
- Protocol clients that handle communication with MCP servers
- Each client maintains a 1:1 connection with a server
-
MCP Servers
- Lightweight programs that expose specific capabilities
- Connect to various data sources (local or remote)
- Implement the MCP protocol to communicate with clients
-
Data Sources
- Local: Files, databases, system services
- Remote: Web APIs, cloud services, other networked resources
Key Features
1. Standardized Access
- Uniform interface for LLMs to access diverse data sources
- Eliminates the need for custom integrations for each tool or data source
2. Security
- Data remains within your infrastructure
- Fine-grained access control
- Secure communication channels
3. Flexibility
- Switch between different LLM providers
- Add or remove data sources without changing core application
- Support for various transport protocols (HTTP, WebSockets, stdio)
4. Extensibility
- Add new capabilities through additional MCP servers
- Support for custom data types and operations
- Versioned API for backward compatibility
Protocol Capabilities
MCP defines several core capabilities that servers can implement:
-
Resources
- Access to structured and unstructured data
- Support for various URI schemes (file://, https://, git://)
- Subscription to resource changes
-
Tools
- Execute functions or operations
- Pass parameters and receive structured results
- Support for both synchronous and asynchronous operations
-
Prompts
- Template management
- Dynamic prompt construction
- Support for multi-step interactions
-
Sampling
- Generate completions based on context
- Control over model parameters
- Support for streaming responses
Implementation Considerations
For MCP Server Developers
- Implement the protocol specification
- Handle authentication and authorization
- Manage resource access and permissions
- Provide appropriate error handling and logging
For MCP Client Developers
- Handle connection management
- Implement capability negotiation
- Manage request/response patterns
- Handle errors and retries
Use Cases
-
AI-Powered Development
- Code completion and generation
- Documentation lookup
- Debugging assistance
-
Enterprise Knowledge
- Internal documentation search
- Knowledge base integration
- Data analysis and visualization
-
Content Creation
- Research assistance
- Content generation
- Fact verification
-
Workflow Automation
- Task automation
- Data processing pipelines
- System administration
Getting Started
Prerequisites
- Node.js (v16+)
- npm or yarn
- Basic understanding of TypeScript/JavaScript
Basic Server Implementation
import { MCPServer, Resource, Tool } from '@modelcontextprotocol/server';
// Create a new MCP server
const server = new MCPServer({
name: 'example-server',
version: '1.0.0'
});
// Define resources
server.resources.register({
name: 'example-resource',
description: 'An example resource',
type: 'text/plain',
async read(uri) {
// Implement resource reading logic
return { content: 'Hello, MCP!', mimeType: 'text/plain' };
}
});
// Define tools
server.tools.register({
name: 'example-tool',
description: 'An example tool',
parameters: {
type: 'object',
properties: {
name: { type: 'string' }
},
required: ['name']
},
async execute(params) {
return { result: `Hello, ${params.name}!` };
}
});
// Start the server
server.start();
Next Steps
- Explore the official MCP documentation
- Review the specification
- Experiment with the reference implementations
- Join the MCP community for support and collaboration
TypeScript SDK Implementation
The official TypeScript SDK for MCP provides a robust way to implement both MCP clients and servers. Here’s an overview of its key features and usage:
Core Components
-
Server
- Handles connection management and protocol compliance
- Routes messages to appropriate handlers
- Manages server lifecycle and capabilities
-
Resources
- Expose data to LLMs (similar to GET endpoints in REST)
- Support static and dynamic content
- Can be parameterized for flexible data access
-
Tools
- Enable LLMs to perform actions with side effects
- Support parameter validation using Zod schemas
- Can make external API calls and process results
Potential Architecture:
File Structure
content-farm/ ├── src/ │ ├── mcp/ # MCP Server implementation │ │ ├── server.ts # Main MCP server setup │ │ ├── resources/ # Resource definitions │ │ │ ├── markdown/ # Markdown resources │ │ │ │ ├── file-resource.ts # File system integration │ │ │ │ └── index.ts # Export markdown resources │ │ │ └── index.ts # Resource exports │ │ │ │ │ ├── tools/ # Tool implementations │ │ │ ├── research/ # Research tools │ │ │ │ ├── web-search.ts # Web search functionality │ │ │ │ └── index.ts # Export research tools │ │ │ └── index.ts # Tool exports │ │ │ │ │ ├── types/ # TypeScript type definitions │ │ │ └── index.ts # Type exports │ │ │ │ │ └── utils/ # Utility functions │ │ ├── fs.ts # File system utilities │ │ ├── research.ts # Research orchestration │ │ └── obsidian.ts # Obsidian integration │ │ │ └── index.ts # Entry point │ └── config/ # Configuration └── mcp.ts # MCP server configuration ├── scripts/ # Utility scripts │ └── start-mcp-server.ts # Script to start the MCP server │
Servers
Server Frameworks
Our choice is Fastify, [[Tooling/Software Development/Frameworks/Web Frameworks/Fastify|Fastify]]
Basic Server Example
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
import { z } from "zod";
// Create an MCP server
const server = new McpServer({
name: "Demo",
version: "1.0.0"
});
// Add a tool
server.tool(
"calculate-bmi",
{
weightKg: z.number(),
heightM: z.number()
},
async ({ weightKg, heightM }) => ({
content: [{
type: "text",
text: String(weightKg / (heightM * heightM))
}]
})
);
// Add a dynamic resource
server.resource(
"user-profile",
new ResourceTemplate("users://{userId}/profile", { list: undefined }),
async (uri, { userId }) => ({
contents: [{
uri: uri.href,
text: `Profile data for user ${userId}`
}]
})
);
// Start the server
const transport = new StdioServerTransport();
await server.connect(transport);
Key Features
-
Type Safety
- Full TypeScript support
- Zod schema validation for tool parameters
- Type-safe resource handling
-
Transport Layers
- Stdio for simple CLI tools
- Streamable HTTP for web applications
- Custom transport support
-
Advanced Capabilities
- Dynamic server registration
- Proxy authorization
- Backward compatibility handling
Integration with Existing Systems
The SDK can be integrated with various data sources and services:
// Example: Database integration
server.tool("query-db",
{ query: z.string() },
async ({ query }) => {
const results = await database.query(query);
return { content: [{ type: "text", text: JSON.stringify(results) }] };
}
);
// Example: External API integration
server.tool("fetch-weather",
{ city: z.string() },
async ({ city }) => {
const response = await fetch(`https://api.weather.com/${city}`);
const data = await response.text();
return { content: [{ type: "text", text: data }] };
}
);
Best Practices
-
Error Handling
- Implement proper error boundaries
- Provide meaningful error messages
- Log errors for debugging
-
Security
- Validate all inputs
- Implement proper authentication
- Follow principle of least privilege
-
Performance
- Cache expensive operations
- Use streaming for large responses
- Monitor resource usage
Questions on Model Context Protocol:
Iterative Markdown Research Assistant
-
Question: How would we use an existing markdown file as a resource, and have the LLM then go do futher web search research using [[Tooling/AI Toolkit/Models/Perplexica|Perplexica]], coming back with improvements to the same markdown file?
-
Findings:
-
MCP Resource for Markdown:
- Markdown files can be exposed as MCP resources using
ResourceTemplate - Supports dynamic file path parameters (e.g.,
markdown://{filePath}) - Handles file I/O operations with proper error handling
- Markdown files can be exposed as MCP resources using
-
Research Integration:
- Perplexica can be integrated via its API for web search functionality
- Research queries can be derived from markdown content or user input
- Supports batch processing of multiple research topics
-
Content Enhancement Workflow:
- Parse markdown to identify research opportunities
- Generate targeted queries for Perplexica
- Process and integrate findings while maintaining markdown structure
- Preserve existing formatting and metadata
-
Implementation Considerations:
- File system access requires proper path resolution
- Need for version control integration to track changes
- Should include user confirmation before overwriting files
- Supports both CLI and GUI interactions
-
Technical Stack:
- MCP TypeScript SDK for protocol implementation
- Fastify for HTTP server (if needed)
- Zod for input validation
- Obsidian API for plugin integration
-
Example Usage:
// Example MCP server setup server.resource("markdown", new ResourceTemplate("markdown://{filePath}"), async (uri, { filePath }) => ({ contents: [{ uri: uri.href, text: await fs.readFile(filePath, 'utf-8'), mimeType: "text/markdown" }] }) ); -
Security Considerations:
- Validate all file system paths
- Implement proper error boundaries
- Consider rate limiting for API calls
- Handle sensitive content appropriately
-
Content Enhancement with Perplexica
For applications that need to enhance content with AI-powered research, here’s how to implement a streaming enhancement feature using Perplexica:
private async enhanceWithPerplexica(content: string, editor: Editor): Promise<void> {
try {
const cursor = editor.getCursor();
const insertPos = { line: cursor.line + 1, ch: 0 };
editor.replaceRange('\n', cursor); // Add space for the response
const requestData = {
query: content,
chatModel: {
provider: 'ollama',
name: 'llama3.2:latest'
},
embeddingModel: {
provider: 'ollama',
name: 'llama3.2:latest'
},
stream: true,
systemInstructions: "Enhance the provided content with relevant research and context."
};
const response = await fetch('http://localhost:3030/api/search', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify(requestData),
});
if (!response.ok) {
throw new Error(`HTTP error! status: ${response.status}`);
}
const reader = response.body?.getReader();
if (!reader) throw new Error('No response body');
let fullResponse = '';
const decoder = new TextDecoder();
while (true) {
const { done, value } = await reader.read();
if (done) break;
const chunk = decoder.decode(value, { stream: true });
fullResponse += chunk;
editor.replaceRange(chunk, insertPos);
// Move cursor to end of inserted text
const lines = fullResponse.split('\n');
const lastLine = lines[lines.length - 1];
editor.setCursor({
line: insertPos.line + Math.max(0, lines.length - 1),
ch: lastLine.length
});
}
} catch (error) {
console.error('Error enhancing content with Perplexica:', error);
const errorMessage = `Error: ${error instanceof Error ? error.message : String(error)}`;
new Notice(errorMessage);
editor.replaceRange(`\n${errorMessage}`, editor.getCursor());
}
}
Key Features
- Streaming Response: Processes and displays content as it’s received
- Real-time Updates: Updates the editor incrementally for better UX
- Error Handling: Comprehensive error handling with user feedback
- Flexible Configuration: Supports different models and providers
Usage Example
// Add this to your command registration
this.addCommand({
id: 'enhance-with-perplexica',
name: 'Enhance with Perplexica',
editorCallback: async (editor: Editor) => {
const selection = editor.getSelection();
if (!selection) {
new Notice('Please select some text to enhance');
return;
}
await this.enhanceWithPerplexica(selection, editor);
}
});