Skip to main content

MCP (Model Context Protocol) Integration

Overview

MCP (Model Context Protocol) is a standard protocol that allows AI agents to communicate with external systems and services. theia AI has built-in support for MCP servers.

What is MCP?

Definition

MCP is an open protocol for connecting AI systems to external data sources and tools:

  • Standardized: Common protocol across different AI tools
  • Server-based: Run MCP servers that expose functionality
  • Tool functions: Agents can call MCP functions like native tools
  • Widely adopted: Thousands of MCP servers available

MCP Architecture

┌─────────────┐         ┌──────────────┐         ┌────────────┐
│ AI Agent │◄──────► │ MCP Client │◄──────► │ MCP Server │
│ (theia) │ calls │ (theia AI) │ protocol│ (Remote) │
└─────────────┘ └──────────────┘ └────────────┘


┌──────────────┐
│ External │
│ System │
│ (GitHub, DB) │
└──────────────┘

Benefits

  • No custom integration code for common services
  • Reusable across different AI tools
  • Community servers for popular services
  • Secure authentication and permissions

Available MCP Servers

Built-in / Common Servers

  1. GitHub MCP Server

    • Repository operations
    • Issue management
    • Pull request handling
    • Comment creation
    • Search functionality
  2. Playwright MCP Server

    • Browser automation
    • Web application testing
    • Screenshot capture
    • Form interaction
    • Navigation control
  3. Google Drive MCP Server

    • File listing
    • Document reading
    • Upload/download
    • Search documents
  4. Slack MCP Server

    • Send messages
    • Read channels
    • User information
    • Channel management
  5. Database MCP Servers

    • PostgreSQL
    • MySQL
    • MongoDB
    • Query execution

Finding MCP Servers

  • Official registry: MCP server directory
  • GitHub: Search for "MCP server"
  • Community: theia community channels
  • Create your own: MCP SDK available

Installing MCP Servers

Method 1: UI Configuration

  1. Open AI Configuration

    Settings → AI Configuration → MCP Servers tab
  2. Add MCP Server

    • Click "Add Server"
    • Select type:
      • Remote URL
      • Local executable
      • npm package
  3. Configure Connection

    Server Name: github-mcp
    Type: Remote
    URL: https://api.mcp.github.com
    Auth: Token
    Token: ${GITHUB_TOKEN}
  4. Test Connection

    • Click "Test"
    • Verify functions appear
    • Check authentication

Method 2: Configuration File

// .theia/mcp-servers.json
{
"servers": {
"github": {
"type": "remote",
"url": "https://api.mcp.github.com",
"auth": {
"type": "token",
"token": "${GITHUB_TOKEN}"
}
},
"playwright": {
"type": "executable",
"command": "npx",
"args": ["@modelcontextprotocol/server-playwright"],
"env": {
"PLAYWRIGHT_BROWSERS_PATH": "${HOME}/.cache/ms-playwright"
}
}
}
}

Method 3: Programmatic Registration

@injectable()
export class MCPServerProvider {
@inject(MCPServerRegistry)
protected registry: MCPServerRegistry;

async registerServers(): Promise<void> {
await this.registry.register({
id: 'github',
name: 'GitHub MCP Server',
url: 'https://api.mcp.github.com',
auth: {
type: 'token',
token: process.env.GITHUB_TOKEN
}
});
}
}

Using MCP in Agents

1. List Available Functions

// In AI Configuration view
MCP Servers[server-name]View Functions

// Or programmatically
const functions = await mcpClient.listFunctions('github');

2. Add to Agent Prompt

# In agent system prompt

You have access to GitHub via MCP:

Available functions:
- create_issue(title, body, labels, assignees)
- list_issues(state, labels, author)
- get_issue(issue_number)
- update_issue(issue_number, title, body, state)
- add_comment(issue_number, body)
- create_pull_request(title, body, head, base)
- list_pull_requests(state, author)
- merge_pull_request(pr_number, merge_method)

Repository: ${GITHUB_REPO}

Use these functions to interact with GitHub when needed.

3. Copy Functions to Prompt

In theia IDE:

  1. Open agent prompt editor
  2. Go to MCP Servers view
  3. Select server (e.g., GitHub)
  4. Click "Copy All Functions"
  5. Paste into prompt template

4. Agent Automatically Calls MCP

Once functions are in the prompt, the agent will:

  • Recognize available MCP functions
  • Determine when to use them
  • Call them with appropriate parameters
  • Process and present results

Example Use Cases

1. GitHub Workflow Automation

# GitHub Assistant Agent

Purpose: Automate GitHub workflows

MCP Server: GitHub

Capabilities:
- Analyze bugs from issues
- Report new bugs
- Review pull requests
- Search code and discussions
- Update project boards

Example workflow:
1. User: "Analyze bug #123"
2. Agent calls: get_issue(123)
3. Agent analyzes issue content
4. Agent calls: list_comments(123)
5. Agent provides analysis

Integration in prompt:
${mcp:github:*}

2. Automated Testing + Bug Reporting

# App Tester Agent

MCP Servers:
- Playwright (browser automation)
- GitHub (bug reporting)

Workflow:
1. Test application using Playwright MCP
- playwright_navigate(url)
- playwright_click(selector)
- playwright_fill(selector, text)
- playwright_screenshot()

2. When bug found:
- github_create_issue(title, body, labels: ['bug'])
- Include screenshot
- Add reproduction steps

3. Continue testing

3. Document Search and Analysis

# Document Assistant Agent

MCP Server: Google Drive

Functions:
- drive_search(query)
- drive_read(file_id)
- drive_list(folder_id)

Example:
User: "Find Q4 reports and summarize key metrics"

Agent:
1. drive_search("Q4 reports 2024")
2. drive_read(file_ids) for top results
3. Extract and summarize metrics
4. Present findings

4. Database Query Assistant

# SQL Assistant Agent

MCP Server: PostgreSQL

Functions:
- postgres_query(sql)
- postgres_tables()
- postgres_schema(table)

Example:
User: "How many active users do we have?"

Agent:
1. postgres_tables() - find user table
2. postgres_schema('users') - check columns
3. postgres_query("SELECT COUNT(*) FROM users WHERE active = true")
4. Present result

MCP Server Configuration

Authentication Patterns

1. Token-Based

{
"auth": {
"type": "token",
"token": "${GITHUB_TOKEN}",
"header": "Authorization",
"prefix": "Bearer"
}
}

2. OAuth

{
"auth": {
"type": "oauth",
"client_id": "${OAUTH_CLIENT_ID}",
"client_secret": "${OAUTH_CLIENT_SECRET}",
"scopes": ["repo", "issues"],
"token_url": "https://github.com/login/oauth/access_token"
}
}

3. API Key

{
"auth": {
"type": "api_key",
"key": "${API_KEY}",
"header": "X-API-Key"
}
}

4. Basic Auth

{
"auth": {
"type": "basic",
"username": "${USERNAME}",
"password": "${PASSWORD}"
}
}

Environment Variables

# .env file
GITHUB_TOKEN=ghp_xxx
GITHUB_REPO=owner/repo
OPENAI_API_KEY=sk-xxx
POSTGRES_CONNECTION=postgresql://user:pass@host/db
// Reference in config
{
"auth": {
"token": "${GITHUB_TOKEN}"
},
"settings": {
"default_repo": "${GITHUB_REPO}"
}
}

Server-Specific Settings

{
"servers": {
"playwright": {
"type": "executable",
"command": "npx",
"args": ["@modelcontextprotocol/server-playwright"],
"settings": {
"headless": true,
"slowMo": 100,
"viewport": {
"width": 1920,
"height": 1080
}
}
}
}
}

Creating Custom MCP Servers

When to Create Custom Server

  • Integrate proprietary internal systems
  • Wrap legacy APIs for AI access
  • Combine multiple services
  • Add custom business logic
  • Enforce security policies

MCP Server Structure

// server.ts
import { MCPServer, Tool } from '@modelcontextprotocol/sdk';

const server = new MCPServer({
name: 'custom-server',
version: '1.0.0'
});

// Register tools
server.addTool({
name: 'custom_function',
description: 'Does something specific',
parameters: {
type: 'object',
properties: {
param1: {
type: 'string',
description: 'First parameter'
}
},
required: ['param1']
},
execute: async (params) => {
// Implementation
return { result: 'success' };
}
});

// Start server
server.listen(3000);

Example: Internal API MCP Server

import { MCPServer } from '@modelcontextprotocol/sdk';
import axios from 'axios';

const server = new MCPServer({
name: 'internal-api',
version: '1.0.0'
});

// Wrap internal API
server.addTool({
name: 'get_customer_data',
description: 'Retrieve customer information',
parameters: {
type: 'object',
properties: {
customer_id: { type: 'string' }
},
required: ['customer_id']
},
execute: async ({ customer_id }) => {
const response = await axios.get(
`https://internal-api.company.com/customers/${customer_id}`,
{
headers: {
'Authorization': `Bearer ${process.env.INTERNAL_API_TOKEN}`
}
}
);
return response.data;
}
});

server.addTool({
name: 'create_support_ticket',
description: 'Create customer support ticket',
parameters: {
type: 'object',
properties: {
customer_id: { type: 'string' },
title: { type: 'string' },
description: { type: 'string' },
priority: {
type: 'string',
enum: ['low', 'medium', 'high']
}
},
required: ['customer_id', 'title', 'description']
},
execute: async (params) => {
const response = await axios.post(
'https://internal-api.company.com/tickets',
params,
{
headers: {
'Authorization': `Bearer ${process.env.INTERNAL_API_TOKEN}`
}
}
);
return response.data;
}
});

server.listen(process.env.PORT || 3000);

Deploying Custom MCP Server

# Dockerfile
FROM node:18
WORKDIR /app
COPY package*.json ./
RUN npm install
COPY . .
RUN npm run build
CMD ["node", "dist/server.js"]
# docker-compose.yml
version: '3.8'
services:
custom-mcp-server:
build: .
ports:
- "3000:3000"
environment:
- INTERNAL_API_TOKEN=${INTERNAL_API_TOKEN}
restart: unless-stopped

Security Considerations

1. Authentication

  • Never hardcode tokens in config files
  • Use environment variables
  • Rotate tokens regularly
  • Scope tokens to minimum permissions

2. Authorization

// In MCP server
const checkPermissions = async (user: string, action: string) => {
// Verify user can perform action
const allowed = await authService.can(user, action);
if (!allowed) {
throw new Error('Unauthorized');
}
};

server.addTool({
name: 'sensitive_operation',
execute: async (params, context) => {
await checkPermissions(context.user, 'sensitive_operation');
// Proceed with operation
}
});

3. Rate Limiting

import rateLimit from 'express-rate-limit';

const limiter = rateLimit({
windowMs: 15 * 60 * 1000, // 15 minutes
max: 100 // limit each IP to 100 requests per windowMs
});

app.use('/mcp', limiter);

4. Input Validation

server.addTool({
name: 'query_database',
execute: async ({ query }) => {
// Validate SQL to prevent injection
if (!isValidSQL(query)) {
throw new Error('Invalid SQL query');
}
// Sanitize input
const sanitized = sanitizeSQL(query);
return await db.query(sanitized);
}
});

5. Audit Logging

server.addMiddleware(async (request, next) => {
// Log all MCP calls
await auditLog.record({
timestamp: new Date(),
user: request.user,
tool: request.tool,
params: request.params,
ip: request.ip
});

const result = await next();

await auditLog.record({
...logEntry,
result: result.success ? 'success' : 'failure',
error: result.error
});

return result;
});

MCP vs Custom Tool Functions

When to Use MCP

✅ Integrating external services ✅ Reusing existing servers ✅ Need authentication/authorization ✅ Want standard protocol ✅ Service used across agents ✅ Community servers available

When to Use Custom Tools

✅ Simple workspace operations ✅ IDE-specific functionality ✅ No external network calls ✅ Agent-specific logic ✅ Performance critical ✅ Complex state management

Hybrid Approach

// Custom tool that uses MCP internally
@injectable()
export class EnhancedGitHubTool implements ToolProvider {
@inject(MCPClient)
protected mcp: MCPClient;

@inject(workspaceService)
protected workspace: workspaceService;

getTool(): Tool {
return {
name: 'analyze_and_report_bug',
description: 'Analyze code and create GitHub issue',
handler: async (args) => {
// Use workspace service (custom)
const code = await this.workspace.readFile(args.file);
const analysis = await this.analyzeCode(code);

// Use MCP for GitHub
const issue = await this.mcp.call('github', 'create_issue', {
title: analysis.title,
body: analysis.description,
labels: analysis.labels
});

return issue;
}
};
}
}

Troubleshooting MCP

Common Issues

  1. Connection Failed

    Error: Cannot connect to MCP server

    Checks:
    - Is server running?
    - Correct URL/port?
    - Firewall blocking?
    - Network accessible?
  2. Authentication Error

    Error: 401 Unauthorized

    Checks:
    - Token valid?
    - Correct token format?
    - Token not expired?
    - Required scopes granted?
  3. Function Not Found

    Error: Function 'xyz' not available

    Checks:
    - Function name spelled correctly?
    - Server provides this function?
    - Server version up to date?
    - Refresh function list
  4. Timeout

    Error: Request timeout

    Checks:
    - Server responsive?
    - Network latency high?
    - Increase timeout setting
    - Check server logs

Debug Mode

{
"servers": {
"github": {
"url": "https://api.mcp.github.com",
"debug": true,
"logging": {
"level": "debug",
"file": "/tmp/mcp-github.log"
}
}
}
}

Testing MCP Servers

# Test MCP server directly
curl -X POST http://localhost:3000/mcp \
-H "Content-Type: application/json" \
-d '{
"method": "tool_call",
"params": {
"name": "list_issues",
"parameters": {
"state": "open"
}
}
}'

Best Practices

1. Function Naming

// ✅ Good: Clear, action-oriented
'create_issue'
'list_pull_requests'
'get_customer_data'

// ❌ Bad: Ambiguous
'issue'
'prs'
'data'

2. Parameter Documentation

{
name: 'create_issue',
parameters: {
type: 'object',
properties: {
title: {
type: 'string',
description: 'Issue title (required, max 200 chars)'
},
body: {
type: 'string',
description: 'Issue description (markdown supported)'
},
labels: {
type: 'array',
items: { type: 'string' },
description: 'Labels to apply (e.g., ["bug", "high-priority"])'
}
},
required: ['title']
}
}

3. Error Handling

execute: async (params) => {
try {
const result = await externalAPI.call(params);
return {
success: true,
data: result
};
} catch (error) {
return {
success: false,
error: {
message: error.message,
code: error.code,
details: error.response?.data
}
};
}
}

4. Response Formatting

// ✅ Return structured data
{
success: true,
data: {
issue_number: 123,
url: 'https://github.com/...',
created_at: '2024-01-01T12:00:00Z'
}
}

// ❌ Return raw strings
"Issue #123 created"

5. Idempotency

execute: async ({ issue_id, comment }) => {
// Check if comment already added
const existing = await getComments(issue_id);
if (existing.some(c => c.body === comment)) {
return { success: true, message: 'Comment already exists' };
}

// Add comment
return await addComment(issue_id, comment);
}

Summary

MCP integration in theia AI provides:

Standardized way to connect to external systems ✅ Reusable servers across agents and tools ✅ Community ecosystem of available servers ✅ Secure authentication and authorization ✅ Easy to configure and use in agents ✅ Flexible - use existing or create custom servers

Key steps:

  1. Install/configure MCP server
  2. Add functions to agent prompt
  3. Agent automatically calls MCP functions
  4. Process and present results

Common use cases:

  • GitHub workflow automation
  • Database queries
  • Cloud service integration
  • Internal API access
  • Browser automation