MCP Client Integration
Angular 21 + Model Context Protocol — connect to an MCP server, discover tools, and invoke them live
What Is MCP?
The Model Context Protocol (MCP) is an open standard that lets AI models discover and call tools exposed by a server — things like database queries, API calls, or any custom logic. Think of it as a structured handshake between a client (your app) and a capability provider (the MCP server).
- Transport: JSON-RPC 2.0 over HTTP POST — plain requests, no magic.
- Handshake:
initialize→notifications/initialized→tools/list - Invocation:
tools/callwith a tool name and typed arguments - Session: The server issues an
Mcp-Session-Idresponse header; include it in every subsequent request.
This page talks to the mcp-server/ Node.js server included in this repo. Start it with npm start from that folder, then click Connect below.
Angular Service Pattern
// mcp-client.service.ts (simplified)
import { inject, signal } from '@angular/core';
import { HttpClient } from '@angular/common/http';
import { firstValueFrom } from 'rxjs';
@Injectable({ providedIn: 'root' })
export class McpClientService {
private http = inject(HttpClient);
private idCounter = 0;
sessionId = signal<string | null>(null);
connected = signal(false);
tools = signal<McpTool[]>([]);
async connect(serverUrl: string) {
// ① Initialize — server responds with its capabilities + session ID header
const initResp = await firstValueFrom(
this.http.post(serverUrl, {
jsonrpc: '2.0', method: 'initialize', id: ++this.idCounter,
params: { protocolVersion: '2024-11-05', capabilities: {},
clientInfo: { name: 'my-client', version: '1.0.0' } },
}, { observe: 'response' })
);
const sid = initResp.headers.get('mcp-session-id');
this.sessionId.set(sid);
// ② Send required handshake notification (no response expected)
await firstValueFrom(
this.http.post(serverUrl,
{ jsonrpc: '2.0', method: 'notifications/initialized' },
{ headers: { 'Mcp-Session-Id': sid! } }
)
);
// ③ Discover tools
const listResp = await firstValueFrom(
this.http.post(serverUrl,
{ jsonrpc: '2.0', method: 'tools/list', params: {}, id: ++this.idCounter },
{ headers: { 'Mcp-Session-Id': sid! } }
)
);
this.tools.set((listResp as any).result.tools);
this.connected.set(true);
}
async callTool(serverUrl: string, name: string, args: Record<string, unknown>) {
const resp = await firstValueFrom(
this.http.post(serverUrl, {
jsonrpc: '2.0', method: 'tools/call', id: ++this.idCounter,
params: { name, arguments: args },
}, { headers: { 'Mcp-Session-Id': this.sessionId()! } })
);
// Result text lives at: resp.result.content[0].text
return (resp as any).result.content[0].text as string;
}
}Live Demo
MCP Server URL (make sure the server is running on port 3001):
Not connected