# MCP4GVA - Python vs TypeScript Comparison
This repository contains **two implementations** of the same MCP server for the GVA GIS ArcGIS API:
1. **Python version** (root directory) - Uses `uvx`
2. **TypeScript version** (`typescript/` directory) - Uses `npx`
Both implementations provide identical functionality, allowing you to compare approaches and learn from the differences.
## Quick Comparison
| Feature | Python | TypeScript |
|---------|--------|------------|
| **Location** | Root directory | `typescript/` directory |
| **Runtime** | Python 3.10+ | Node.js 18+ |
| **Package Manager** | uv/uvx | npm/npx |
| **MCP SDK** | `mcp` | `@modelcontextprotocol/sdk` |
| **HTTP Client** | `requests` | `node-fetch` |
| **Type System** | Type hints (optional) | TypeScript (enforced) |
| **Build Step** | ❌ Not needed | ✅ Required (`tsc`) |
| **Entry Point** | `mcp4gva.server:main` | `build/index.js` |
| **Config Command** | `uvx mcp4gva` | `npx -y mcp4gva-typescript` |
## File Structure Comparison
### Python Version
```
mcp4gva/ # Root directory
├── mcp4gva/
│ ├── __init__.py
│ └── server.py # ~265 lines
├── pyproject.toml # Package config
├── requirements.txt
├── gva_gis_client.py # Bonus: standalone client
├── examples.py # Bonus: examples
└── README.md
```
### TypeScript Version
```
typescript/
├── src/
│ └── index.ts # ~360 lines
├── build/ # Generated by tsc
├── package.json # Package config
├── tsconfig.json # TypeScript config
└── README.md
```
## Code Comparison
### 1. Server Initialization
**Python:**
```python
from mcp.server import Server
from mcp.types import Tool, TextContent
import mcp.server.stdio
app = Server("mcp4gva")
```
**TypeScript:**
```typescript
import { Server } from "@modelcontextprotocol/sdk/server/index.js";
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
const server = new Server(
{ name: "mcp4gva-typescript", version: "0.1.0" },
{ capabilities: { tools: {} } }
);
```
### 2. Listing Tools
**Python:**
```python
@app.list_tools()
async def list_tools() -> list[Tool]:
return [
Tool(
name="gva_layer_info",
description="Get metadata...",
inputSchema={...}
),
# ...
]
```
**TypeScript:**
```typescript
server.setRequestHandler(ListToolsRequestSchema, async () => {
return {
tools: [
{
name: "gva_layer_info",
description: "Get metadata...",
inputSchema: {...}
},
// ...
]
};
});
```
### 3. Handling Tool Calls
**Python:**
```python
@app.call_tool()
async def call_tool(name: str, arguments: Any) -> list[TextContent]:
if name == "gva_layer_info":
data = make_request(url, params)
return [TextContent(
type="text",
text=json.dumps(result, indent=2)
)]
```
**TypeScript:**
```typescript
server.setRequestHandler(CallToolRequestSchema, async (request) => {
const { name, arguments: args } = request.params;
if (name === "gva_layer_info") {
const data = await makeRequest(url, params);
return {
content: [{
type: "text",
text: JSON.stringify(result, null, 2)
}]
};
}
});
```
### 4. HTTP Requests
**Python:**
```python
import requests
def make_request(url: str, params: dict) -> dict:
headers = {
'User-Agent': 'Mozilla/5.0...',
'Accept': 'application/json'
}
response = requests.get(url, params=params, headers=headers)
response.raise_for_status()
return response.json()
```
**TypeScript:**
```typescript
import fetch from "node-fetch";
async function makeRequest(url: string, params: RequestParams): Promise<ApiResponse> {
const queryParams = new URLSearchParams();
for (const [key, value] of Object.entries(params)) {
queryParams.append(key, String(value));
}
const response = await fetch(`${url}?${queryParams}`, {
headers: {
"User-Agent": "Mozilla/5.0...",
"Accept": "application/json"
}
});
if (!response.ok) {
throw new Error(`HTTP error! status: ${response.status}`);
}
return await response.json() as ApiResponse;
}
```
### 5. Main Entry Point
**Python:**
```python
def main():
"""Main entry point for the MCP server"""
import asyncio
asyncio.run(run_server())
async def run_server():
"""Run the async server"""
async with mcp.server.stdio.stdio_server() as (read_stream, write_stream):
await app.run(read_stream, write_stream, app.create_initialization_options())
if __name__ == "__main__":
main()
```
**TypeScript:**
```typescript
async function main() {
const server = createServer();
const transport = new StdioServerTransport();
await server.connect(transport);
console.error("MCP4GVA TypeScript server running on stdio");
}
main().catch((error) => {
console.error("Fatal error:", error);
process.exit(1);
});
```
## Installation & Usage
### Python Version
```bash
# Install uv
curl -LsSf https://astral.sh/uv/install.sh | sh
# Configure Claude Desktop
{
"mcpServers": {
"mcp4gva": {
"command": "uvx",
"args": ["--from", "/path/to/mcp4gva", "mcp4gva"]
}
}
}
# Test manually
uvx --from . mcp4gva
```
### TypeScript Version
```bash
# Install dependencies
cd typescript
npm install
# Build
npm run build
# Configure Claude Desktop
{
"mcpServers": {
"mcp4gva-ts": {
"command": "node",
"args": ["/path/to/mcp4gva/typescript/build/index.js"]
}
}
}
# Test manually
npm run dev
```
## Key Differences
### 1. Type Safety
**Python:** Optional type hints
```python
def make_request(url: str, params: dict) -> dict:
# Type hints are optional and not enforced at runtime
pass
```
**TypeScript:** Compile-time type checking
```typescript
async function makeRequest(url: string, params: RequestParams): Promise<ApiResponse> {
// Types are checked at compile time
// Compilation fails if types don't match
}
```
### 2. Async/Await
**Python:** Built-in asyncio
```python
async def call_tool(name: str, arguments: Any) -> list[TextContent]:
data = make_request(url, params) # Synchronous call
return [TextContent(...)]
```
**TypeScript:** Promise-based
```typescript
async function callTool(name: string, args: any): Promise<Content[]> {
const data = await makeRequest(url, params); // Must await
return [{ type: "text", text: "..." }];
}
```
### 3. Error Handling
**Python:** Try-except
```python
try:
data = make_request(url, params)
except requests.RequestException as e:
logger.error(f"Request failed: {e}")
raise
```
**TypeScript:** Try-catch with instanceof
```typescript
try {
const data = await makeRequest(url, params);
} catch (error) {
const errorMessage = error instanceof Error ? error.message : String(error);
console.error(`Request failed: ${errorMessage}`);
throw error;
}
```
### 4. Dependency Management
**Python (pyproject.toml):**
```toml
[project]
dependencies = [
"mcp>=0.9.0",
"requests>=2.31.0",
]
[project.scripts]
mcp4gva = "mcp4gva.server:main"
```
**TypeScript (package.json):**
```json
{
"dependencies": {
"@modelcontextprotocol/sdk": "^0.5.0",
"node-fetch": "^3.3.2"
},
"bin": {
"mcp4gva-ts": "./build/index.js"
}
}
```
## Performance
Both implementations have similar performance:
- **Startup time:** Python slightly faster (no build step needed at runtime)
- **Runtime performance:** Comparable for I/O-bound operations like HTTP requests
- **Memory usage:** Similar, both lightweight
## Which Should You Choose?
### Choose Python if:
- You're more comfortable with Python
- You want simpler deployment (no build step)
- Your team already uses Python tooling
- You want the bonus standalone client and examples
### Choose TypeScript if:
- You prefer strong typing and compile-time checks
- Your team uses JavaScript/TypeScript
- You want better IDE support and autocomplete
- You're building on top of existing Node.js infrastructure
## Learning From Both
This repository is designed for learning. You can:
1. **Compare implementations side by side** - See how the same functionality is implemented in both languages
2. **Test both versions** - Configure both in Claude Desktop and compare behavior
3. **Modify and experiment** - Try adding a new tool to both versions
4. **Understand MCP SDK differences** - See how Python and TypeScript SDKs differ
## Contributing
Both implementations should be kept in sync feature-wise. When adding a new tool:
1. Implement it in both Python and TypeScript
2. Update both READMEs
3. Test both versions
4. Update this comparison document
## Resources
- [MCP Documentation](https://modelcontextprotocol.io/)
- [MCP Python SDK](https://github.com/modelcontextprotocol/python-sdk)
- [MCP TypeScript SDK](https://github.com/modelcontextprotocol/typescript-sdk)
- [ArcGIS REST API](https://developers.arcgis.com/rest/)
- [GVA GIS API](https://gvagis.icv.gva.es/server/rest/services)