This is page 1 of 2. Use http://codebase.md/tolik-unicornrider/mcp_scraper?page={x} to view the full context.
# Directory Structure
```
├── .gitignore
├── jest.config.js
├── mcp_docs
│ ├── mcp-llms-full.txt
│ └── mcp-typescript-sdk.txt
├── package-lock.json
├── package.json
├── README.md
├── src
│ ├── cli.ts
│ ├── data_processing.test.ts
│ ├── data_processing.ts
│ └── index.ts
├── test.html
└── tsconfig.json
```
# Files
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
```
node_modules
build
```
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
```markdown
# Website Scraper
A command-line tool and MCP server for scraping websites and converting HTML to Markdown.
## Features
- Extracts meaningful content from web pages using Mozilla's [Readability](https://github.com/mozilla/readability) library (the same engine used in Firefox's Reader View)
- Converts clean HTML to high-quality Markdown with TurndownService
- Securely handles HTML by removing potentially harmful script tags
- Works as both a command-line tool and an MCP server
- Supports direct conversion of local HTML files to Markdown
## Installation
```bash
# Install dependencies
npm install
# Build the project
npm run build
# Optionally, install globally
npm install -g .
```
## Usage
### CLI Mode
```bash
# Print output to console
scrape https://example.com
# Save output to a file
scrape https://example.com output.md
# Convert a local HTML file to Markdown
scrape --html-file input.html
# Convert a local HTML file and save output to a file
scrape --html-file input.html output.md
# Show help
scrape --help
# Or run via npm script
npm run start:cli -- https://example.com
```
### MCP Server Mode
This tool can be used as a Model Context Protocol (MCP) server:
```bash
# Start in MCP server mode
npm start
```
## Code Structure
- `src/index.ts` - Core functionality and MCP server implementation
- `src/cli.ts` - Command-line interface implementation
- `src/data_processing.ts` - HTML to Markdown conversion functionality
## API
The tool exports the following functions:
```typescript
// Scrape a website and convert to Markdown
import { scrapeToMarkdown } from './build/index.js';
// Convert HTML string to Markdown directly
import { htmlToMarkdown } from './build/data_processing.js';
async function example() {
// Web scraping
const markdown = await scrapeToMarkdown('https://example.com');
console.log(markdown);
// Direct HTML conversion
const html = '<h1>Hello World</h1><p>This is <strong>bold</strong> text.</p>';
const md = htmlToMarkdown(html);
console.log(md);
}
```
## License
ISC
```
--------------------------------------------------------------------------------
/jest.config.js:
--------------------------------------------------------------------------------
```javascript
export default {
preset: 'ts-jest',
testEnvironment: 'node',
extensionsToTreatAsEsm: ['.ts'],
moduleNameMapper: {
'^(\\.{1,2}/.*)\\.js$': '$1',
},
transform: {
'^.+\\.tsx?$': [
'ts-jest',
{
useESM: true,
},
],
},
};
```
--------------------------------------------------------------------------------
/tsconfig.json:
--------------------------------------------------------------------------------
```json
{
"compilerOptions": {
"target": "ES2022",
"module": "Node16",
"moduleResolution": "Node16",
"outDir": "./build",
"rootDir": "./src",
"strict": true,
"esModuleInterop": true,
"skipLibCheck": true,
"forceConsistentCasingInFileNames": true
},
"include": ["src/**/*"],
"exclude": ["node_modules"]
}
```
--------------------------------------------------------------------------------
/src/data_processing.ts:
--------------------------------------------------------------------------------
```typescript
import TurndownService from "turndown";
/**
* Converts raw HTML to Markdown using TurndownService
* Removes script tags for security and cleaner output
* @param html Raw HTML string to convert
* @returns Markdown string
*/
export function htmlToMarkdown(html: string): string {
// Remove script tags and their content before conversion
const cleanHtml = html.replace(/<script\b[^<]*(?:(?!<\/script>)<[^<]*)*<\/script>/gi, '');
const turndownService = new TurndownService({
codeBlockStyle: 'fenced',
emDelimiter: '_'
});
return turndownService.turndown(cleanHtml);
}
```
--------------------------------------------------------------------------------
/test.html:
--------------------------------------------------------------------------------
```html
<!DOCTYPE html>
<html>
<head>
<title>Test HTML Document</title>
<script>
// This script should be removed in markdown
console.log("This should not appear in the output");
</script>
<style>
body { font-family: Arial, sans-serif; }
</style>
</head>
<body>
<h1>Test HTML Document</h1>
<p>This is a <strong>test</strong> document with some <em>emphasized</em> text.</p>
<h2>Features List</h2>
<ul>
<li>Headings</li>
<li>Paragraphs</li>
<li>Formatting (<strong>bold</strong>, <em>italic</em>)</li>
<li>Lists</li>
<li><a href="https://example.com">Links</a></li>
<li>Code blocks</li>
</ul>
<h2>Code Example</h2>
<pre><code>function test() {
console.log("Hello, world!");
return true;
}</code></pre>
<script>
// This inline script should also be removed
document.getElementById("test").innerHTML = "Modified content";
</script>
</body>
</html>
```
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
```json
{
"name": "website-scraper",
"version": "1.0.0",
"description": "Command-line tool and MCP server for scraping websites and converting HTML to Markdown",
"main": "build/index.js",
"keywords": [],
"author": "",
"license": "ISC",
"type": "module",
"bin": {
"scrape": "./build/cli.js"
},
"scripts": {
"build": "tsc && node -e \"require('fs').chmodSync('build/cli.js', '755')\"",
"start": "npm run build && node build/index.js",
"start:cli": "npm run build && node build/cli.js",
"test": "node --experimental-vm-modules node_modules/jest/bin/jest.js",
"test:watch": "node --experimental-vm-modules node_modules/jest/bin/jest.js --watch"
},
"files": [
"build"
],
"dependencies": {
"@modelcontextprotocol/sdk": "^1.6.1",
"@mozilla/readability": "^0.6.0",
"jsdom": "^26.0.0",
"node-html-markdown": "^1.3.0",
"turndown": "^7.2.0",
"zod": "^3.24.2"
},
"devDependencies": {
"@types/jest": "^29.5.14",
"@types/jsdom": "^21.1.7",
"@types/node": "^22.13.9",
"@types/turndown": "^5.0.5",
"jest": "^29.7.0",
"ts-jest": "^29.2.6",
"typescript": "^5.8.2"
}
}
```
--------------------------------------------------------------------------------
/src/cli.ts:
--------------------------------------------------------------------------------
```typescript
#!/usr/bin/env node
import { scrapeToMarkdown } from './index.js';
import { htmlToMarkdown } from './data_processing.js';
import fs from 'fs/promises';
import path from 'path';
/**
* CLI handler for website scraping and HTML conversion
*/
async function runCli() {
const args = process.argv.slice(2);
// Basic help
if (args.includes('--help') || args.includes('-h') || args.length === 0) {
console.log(`
Usage: scrape <url> [output_file]
or: scrape --html-file <html_file> [output_file]
Options:
--help, -h Show this help message
--html-file Convert a local HTML file to Markdown instead of scraping a URL
Arguments:
url/html_file URL to scrape or path to HTML file (required)
output_file Output file path (optional, if not provided output is printed to stdout)
`);
process.exit(0);
}
// Check if we're converting a local HTML file
const htmlFileMode = args.includes('--html-file');
let targetInput: string;
let outputFile: string | undefined;
if (htmlFileMode) {
const fileArgIndex = args.indexOf('--html-file') + 1;
if (fileArgIndex >= args.length) {
console.error('Error: No HTML file specified after --html-file');
process.exit(1);
}
targetInput = args[fileArgIndex];
outputFile = args[fileArgIndex + 1];
} else {
targetInput = args[0];
outputFile = args[1];
}
try {
let markdown: string;
if (htmlFileMode) {
// Direct HTML file to Markdown conversion
try {
const htmlContent = await fs.readFile(targetInput, 'utf-8');
markdown = htmlToMarkdown(htmlContent);
} catch (err: any) {
throw new Error(`Error reading HTML file: ${err.message}`);
}
} else {
// Web scraping mode
markdown = await scrapeToMarkdown(targetInput);
}
if (outputFile) {
await fs.writeFile(outputFile, markdown);
console.error(`Markdown saved to: ${outputFile}`);
} else {
console.log(markdown);
}
} catch (error: any) {
console.error(error.message);
process.exit(1);
}
}
// Run the CLI
runCli().catch((error) => {
console.error("Fatal error:", error);
process.exit(1);
});
```
--------------------------------------------------------------------------------
/src/index.ts:
--------------------------------------------------------------------------------
```typescript
#!/usr/bin/env node
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
import { z } from "zod";
import { Readability } from '@mozilla/readability';
import { JSDOM } from 'jsdom';
import { htmlToMarkdown } from './data_processing.js';
/**
* Scrapes a website and converts the HTML content to markdown
* @param url The URL to scrape
* @returns The markdown content as a string
*/
export async function scrapeToMarkdown(url: string): Promise<string> {
try {
// Fetch the HTML content from the provided URL with proper headers
const response = await fetch(url, {
headers: {
'User-Agent': 'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/119.0.0.0 Safari/537.36',
'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8',
'Accept-Language': 'en-US,en;q=0.5',
}
});
if (!response.ok) {
throw new Error(`Failed to fetch URL: ${response.status}`);
}
// Get content type to check encoding
const contentType = response.headers.get('content-type') || '';
const htmlContent = await response.text();
// Parse the HTML using JSDOM with the URL to resolve relative links
const dom = new JSDOM(htmlContent, {
url,
pretendToBeVisual: true, // This helps with some interactive content
});
// Extract the main content using Readability
const reader = new Readability(dom.window.document);
const article = reader.parse();
if (!article || !article.content) {
throw new Error("Failed to parse article content");
}
// Convert the cleaned article HTML to Markdown using htmlToMarkdown
let markdown = htmlToMarkdown(article.content);
// Simple post-processing to improve code blocks with language hints
markdown = markdown.replace(/```\n(class|function|import|const|let|var|if|for|while)/g, '```javascript\n$1');
markdown = markdown.replace(/```\n(def|class|import|from|with|if|for|while)(\s+)/g, '```python\n$1$2');
return markdown;
} catch (error: any) {
throw new Error(`Scraping error: ${error.message}`);
}
}
// Create an MCP server instance
const server = new McpServer({
name: "ScrapeServer",
version: "1.0.0"
});
// Register the "scrape-to-markdown" tool
server.tool(
"scrape-to-markdown",
{ url: z.string().url() },
async ({ url }) => {
try {
const markdown = await scrapeToMarkdown(url);
// Return the markdown as the tool result
return {
content: [{ type: "text", text: markdown }]
};
} catch (error: any) {
// Handle errors gracefully
return {
content: [{ type: "text", text: `Error: ${error.message}` }],
isError: true
};
}
}
);
// Start the MCP server using stdio transport
// const transport = new StdioServerTransport();
// await server.connect(transport);
async function main() {
// Create a stdio transport for communication
// This allows the server to communicate with clients via standard input/output
const transport = new StdioServerTransport();
// Connect the server to the transport
// This starts listening for incoming messages and enables communication
await server.connect(transport);
// Log a message to indicate the server is running
// Note: Using console.error instead of console.log because stdout is used for MCP communication
console.error("Weather MCP Server running on stdio");
}
// Call the main function and handle any fatal errors
main().catch((error) => {
console.error("Fatal error in main():", error);
process.exit(1); // Exit with error code 1 if there's a fatal error
});
```
--------------------------------------------------------------------------------
/src/data_processing.test.ts:
--------------------------------------------------------------------------------
```typescript
import { htmlToMarkdown } from './data_processing.js';
describe('htmlToMarkdown', () => {
test('converts basic HTML to markdown', () => {
const html = '<p>Hello world</p>';
expect(htmlToMarkdown(html)).toBe('Hello world');
});
test('converts headings', () => {
const html = '<h1>Title</h1><h2>Subtitle</h2>';
expect(htmlToMarkdown(html)).toBe('Title\n=====\n\nSubtitle\n--------');
});
test('converts emphasis using underscores', () => {
const html = '<em>emphasized text</em>';
expect(htmlToMarkdown(html)).toBe('_emphasized text_');
});
test('converts strong', () => {
const html = '<strong>bold text</strong>';
expect(htmlToMarkdown(html)).toBe('**bold text**');
});
test('converts code blocks with fencing', () => {
const html = '<pre><code>const x = 1;</code></pre>';
expect(htmlToMarkdown(html)).toBe('```\nconst x = 1;\n```');
});
test('converts links', () => {
const html = '<a href="https://example.com">Example</a>';
expect(htmlToMarkdown(html)).toBe('[Example](https://example.com)');
});
test('converts lists', () => {
const html = '<ul><li>Item 1</li><li>Item 2</li></ul>';
expect(htmlToMarkdown(html)).toBe('* Item 1\n* Item 2');
});
test('converts nested HTML structures', () => {
const html = '<div><h1>Title</h1><p>Paragraph with <strong>bold</strong> and <em>emphasis</em>.</p></div>';
expect(htmlToMarkdown(html)).toBe('Title\n=====\n\nParagraph with **bold** and _emphasis_.');
});
test('handles empty input', () => {
expect(htmlToMarkdown('')).toBe('');
});
test('handles input with no HTML tags', () => {
const text = 'Plain text without any HTML';
expect(htmlToMarkdown(text)).toBe('Plain text without any HTML');
});
test('handles complex HTML page with script tags', () => {
const html = `
<!DOCTYPE html>
<html>
<head>
<title>Test Page</title>
<script>
console.log("This script should be removed");
function test() {
return "Hello World";
}
</script>
<style>
body { font-family: Arial, sans-serif; }
</style>
</head>
<body>
<header>
<h1>Page Header</h1>
<nav>
<ul>
<li><a href="#section1">Section 1</a></li>
<li><a href="#section2">Section 2</a></li>
</ul>
</nav>
</header>
<main>
<section id="section1">
<h2>Section 1 Title</h2>
<p>This is <em>emphasized</em> and <strong>strong</strong> text.</p>
<script>document.write("This should not appear in markdown");</script>
<pre><code>const codeExample = "This should be formatted as code";</code></pre>
</section>
<section id="section2">
<h2>Section 2 Title</h2>
<p>Another paragraph with a <a href="https://example.com">link</a>.</p>
<table>
<tr>
<th>Header 1</th>
<th>Header 2</th>
</tr>
<tr>
<td>Cell 1</td>
<td>Cell 2</td>
</tr>
</table>
</section>
</main>
<footer>
<p>Page Footer</p>
<script>
// This script should also be removed
const footer = document.querySelector('footer');
</script>
</footer>
</body>
</html>
`;
const expectedMarkdown = `Test Page body { font-family: Arial, sans-serif; }
Page Header
===========
* [Section 1](#section1)
* [Section 2](#section2)
Section 1 Title
---------------
This is _emphasized_ and **strong** text.
\`\`\`
const codeExample = "This should be formatted as code";
\`\`\`
Section 2 Title
---------------
Another paragraph with a [link](https://example.com).
Header 1
Header 2
Cell 1
Cell 2
Page Footer`.trim();
const output = htmlToMarkdown(html).trim();
expect(output).toBe(expectedMarkdown);
});
});
```
--------------------------------------------------------------------------------
/mcp_docs/mcp-typescript-sdk.txt:
--------------------------------------------------------------------------------
```
# MCP TypeScript SDK  
## Table of Contents
- [Overview](#overview)
- [Installation](#installation)
- [Quickstart](#quickstart)
- [What is MCP?](#what-is-mcp)
- [Core Concepts](#core-concepts)
- [Server](#server)
- [Resources](#resources)
- [Tools](#tools)
- [Prompts](#prompts)
- [Running Your Server](#running-your-server)
- [stdio](#stdio)
- [HTTP with SSE](#http-with-sse)
- [Testing and Debugging](#testing-and-debugging)
- [Examples](#examples)
- [Echo Server](#echo-server)
- [SQLite Explorer](#sqlite-explorer)
- [Advanced Usage](#advanced-usage)
- [Low-Level Server](#low-level-server)
- [Writing MCP Clients](#writing-mcp-clients)
- [Server Capabilities](#server-capabilities)
## Overview
The Model Context Protocol allows applications to provide context for LLMs in a standardized way, separating the concerns of providing context from the actual LLM interaction. This TypeScript SDK implements the full MCP specification, making it easy to:
- Build MCP clients that can connect to any MCP server
- Create MCP servers that expose resources, prompts and tools
- Use standard transports like stdio and SSE
- Handle all MCP protocol messages and lifecycle events
## Installation
```bash
npm install @modelcontextprotocol/sdk
```
## Quick Start
Let's create a simple MCP server that exposes a calculator tool and some data:
```typescript
import { McpServer, ResourceTemplate } 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 an addition tool
server.tool("add",
{ a: z.number(), b: z.number() },
async ({ a, b }) => ({
content: [{ type: "text", text: String(a + b) }]
})
);
// Add a dynamic greeting resource
server.resource(
"greeting",
new ResourceTemplate("greeting://{name}", { list: undefined }),
async (uri, { name }) => ({
contents: [{
uri: uri.href,
text: `Hello, ${name}!`
}]
})
);
// Start receiving messages on stdin and sending messages on stdout
const transport = new StdioServerTransport();
await server.connect(transport);
```
## What is MCP?
The [Model Context Protocol (MCP)](https://modelcontextprotocol.io) lets you build servers that expose data and functionality to LLM applications in a secure, standardized way. Think of it like a web API, but specifically designed for LLM interactions. MCP servers can:
- Expose data through **Resources** (think of these sort of like GET endpoints; they are used to load information into the LLM's context)
- Provide functionality through **Tools** (sort of like POST endpoints; they are used to execute code or otherwise produce a side effect)
- Define interaction patterns through **Prompts** (reusable templates for LLM interactions)
- And more!
## Core Concepts
### Server
The McpServer is your core interface to the MCP protocol. It handles connection management, protocol compliance, and message routing:
```typescript
const server = new McpServer({
name: "My App",
version: "1.0.0"
});
```
### Resources
Resources are how you expose data to LLMs. They're similar to GET endpoints in a REST API - they provide data but shouldn't perform significant computation or have side effects:
```typescript
// Static resource
server.resource(
"config",
"config://app",
async (uri) => ({
contents: [{
uri: uri.href,
text: "App configuration here"
}]
})
);
// Dynamic resource with parameters
server.resource(
"user-profile",
new ResourceTemplate("users://{userId}/profile", { list: undefined }),
async (uri, { userId }) => ({
contents: [{
uri: uri.href,
text: `Profile data for user ${userId}`
}]
})
);
```
### Tools
Tools let LLMs take actions through your server. Unlike resources, tools are expected to perform computation and have side effects:
```typescript
// Simple tool with parameters
server.tool(
"calculate-bmi",
{
weightKg: z.number(),
heightM: z.number()
},
async ({ weightKg, heightM }) => ({
content: [{
type: "text",
text: String(weightKg / (heightM * heightM))
}]
})
);
// Async tool with external API call
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 }]
};
}
);
```
### Prompts
Prompts are reusable templates that help LLMs interact with your server effectively:
```typescript
server.prompt(
"review-code",
{ code: z.string() },
({ code }) => ({
messages: [{
role: "user",
content: {
type: "text",
text: `Please review this code:\n\n${code}`
}
}]
})
);
```
## Running Your Server
MCP servers in TypeScript need to be connected to a transport to communicate with clients. How you start the server depends on the choice of transport:
### stdio
For command-line tools and direct integrations:
```typescript
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
const server = new McpServer({
name: "example-server",
version: "1.0.0"
});
// ... set up server resources, tools, and prompts ...
const transport = new StdioServerTransport();
await server.connect(transport);
```
### HTTP with SSE
For remote servers, start a web server with a Server-Sent Events (SSE) endpoint, and a separate endpoint for the client to send its messages to:
```typescript
import express from "express";
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
import { SSEServerTransport } from "@modelcontextprotocol/sdk/server/sse.js";
const server = new McpServer({
name: "example-server",
version: "1.0.0"
});
// ... set up server resources, tools, and prompts ...
const app = express();
app.get("/sse", async (req, res) => {
const transport = new SSEServerTransport("/messages", res);
await server.connect(transport);
});
app.post("/messages", async (req, res) => {
// Note: to support multiple simultaneous connections, these messages will
// need to be routed to a specific matching transport. (This logic isn't
// implemented here, for simplicity.)
await transport.handlePostMessage(req, res);
});
app.listen(3001);
```
### Testing and Debugging
To test your server, you can use the [MCP Inspector](https://github.com/modelcontextprotocol/inspector). See its README for more information.
## Examples
### Echo Server
A simple server demonstrating resources, tools, and prompts:
```typescript
import { McpServer, ResourceTemplate } from "@modelcontextprotocol/sdk/server/mcp.js";
import { z } from "zod";
const server = new McpServer({
name: "Echo",
version: "1.0.0"
});
server.resource(
"echo",
new ResourceTemplate("echo://{message}", { list: undefined }),
async (uri, { message }) => ({
contents: [{
uri: uri.href,
text: `Resource echo: ${message}`
}]
})
);
server.tool(
"echo",
{ message: z.string() },
async ({ message }) => ({
content: [{ type: "text", text: `Tool echo: ${message}` }]
})
);
server.prompt(
"echo",
{ message: z.string() },
({ message }) => ({
messages: [{
role: "user",
content: {
type: "text",
text: `Please process this message: ${message}`
}
}]
})
);
```
### SQLite Explorer
A more complex example showing database integration:
```typescript
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
import sqlite3 from "sqlite3";
import { promisify } from "util";
import { z } from "zod";
const server = new McpServer({
name: "SQLite Explorer",
version: "1.0.0"
});
// Helper to create DB connection
const getDb = () => {
const db = new sqlite3.Database("database.db");
return {
all: promisify<string, any[]>(db.all.bind(db)),
close: promisify(db.close.bind(db))
};
};
server.resource(
"schema",
"schema://main",
async (uri) => {
const db = getDb();
try {
const tables = await db.all(
"SELECT sql FROM sqlite_master WHERE type='table'"
);
return {
contents: [{
uri: uri.href,
text: tables.map((t: {sql: string}) => t.sql).join("\n")
}]
};
} finally {
await db.close();
}
}
);
server.tool(
"query",
{ sql: z.string() },
async ({ sql }) => {
const db = getDb();
try {
const results = await db.all(sql);
return {
content: [{
type: "text",
text: JSON.stringify(results, null, 2)
}]
};
} catch (err: unknown) {
const error = err as Error;
return {
content: [{
type: "text",
text: `Error: ${error.message}`
}],
isError: true
};
} finally {
await db.close();
}
}
);
```
## Advanced Usage
### Low-Level Server
For more control, you can use the low-level Server class directly:
```typescript
import { Server } from "@modelcontextprotocol/sdk/server/index.js";
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
import {
ListPromptsRequestSchema,
GetPromptRequestSchema
} from "@modelcontextprotocol/sdk/types.js";
const server = new Server(
{
name: "example-server",
version: "1.0.0"
},
{
capabilities: {
prompts: {}
}
}
);
server.setRequestHandler(ListPromptsRequestSchema, async () => {
return {
prompts: [{
name: "example-prompt",
description: "An example prompt template",
arguments: [{
name: "arg1",
description: "Example argument",
required: true
}]
}]
};
});
server.setRequestHandler(GetPromptRequestSchema, async (request) => {
if (request.params.name !== "example-prompt") {
throw new Error("Unknown prompt");
}
return {
description: "Example prompt",
messages: [{
role: "user",
content: {
type: "text",
text: "Example prompt text"
}
}]
};
});
const transport = new StdioServerTransport();
await server.connect(transport);
```
### Writing MCP Clients
The SDK provides a high-level client interface:
```typescript
import { Client } from "@modelcontextprotocol/sdk/client/index.js";
import { StdioClientTransport } from "@modelcontextprotocol/sdk/client/stdio.js";
const transport = new StdioClientTransport({
command: "node",
args: ["server.js"]
});
const client = new Client(
{
name: "example-client",
version: "1.0.0"
},
{
capabilities: {
prompts: {},
resources: {},
tools: {}
}
}
);
await client.connect(transport);
// List prompts
const prompts = await client.listPrompts();
// Get a prompt
const prompt = await client.getPrompt("example-prompt", {
arg1: "value"
});
// List resources
const resources = await client.listResources();
// Read a resource
const resource = await client.readResource("file:///example.txt");
// Call a tool
const result = await client.callTool({
name: "example-tool",
arguments: {
arg1: "value"
}
});
```
## Documentation
- [Model Context Protocol documentation](https://modelcontextprotocol.io)
- [MCP Specification](https://spec.modelcontextprotocol.io)
- [Example Servers](https://github.com/modelcontextprotocol/servers)
## Contributing
Issues and pull requests are welcome on GitHub at https://github.com/modelcontextprotocol/typescript-sdk.
## License
This project is licensed under the MIT License—see the [LICENSE](LICENSE) file for details.
```