Truy cập resources từ client

8 — MCPTrung cấp15 phút

Bạn sẽ học được
  • Client enumerate và read resources
  • Inject resource content vào Claude prompt
  • UX pattern: @mentions, file pickers
  • Caching resources client-side

Client operations

List

Read

resources = await client.list_resources()
for r in resources:
    print(f"URI: {r.uri}")
    print(f"Name: {r.name}")
    print(f"Description: {r.description}")

Read

result = await client.read_resource("docs://report.pdf")

# Content parts
for content in result.contents:
    if content.type == "text":
        print(content.text)
    elif content.type == "blob":
        print(f"Binary data: {len(content.blob)} bytes")

UX: @mentions

User references resource trong chat:

Implementation

You: Summarize @docs://report.pdf

Detect @uri → fetch resource → include in context.

Implementation

User: @docs://report.pdf what's the main finding?

→ expanded:

import re

URI_PATTERN = re.compile(r"@(\w+://[^\s]+)")


async def expand_mentions(user_input: str, client) -> str:
    """Replace @mentions with resource content."""
    uris = URI_PATTERN.findall(user_input)
    
    for uri in uris:
        try:
            result = await client.read_resource(uri)
            content = "\n".join(c.text for c in result.contents if c.type == "text")
            user_input = user_input.replace(f"@{uri}", f"\n<{uri}>\n{content}\n</{uri}>\n")
        except Exception as e:
            print(f"Error reading {uri}: {e}")
    
    return user_input


# In chat loop
user_input = input("You: ")
expanded = await expand_mentions(user_input, client)
messages.append({"role": "user", "content": expanded})

UX: @mentions (tiếp)

Claude has full context.

<docs://report.pdf>
Q4 report content...
</docs://report.pdf>

what's the main finding?

UX: Resource picker

Menu for user:

Works for CLI. UI uses dropdown, modal, etc.

async def select_resource(client):
    resources = await client.list_resources()
    print("Select resource:")
    for i, r in enumerate(resources):
        print(f"  {i+1}. {r.name} ({r.uri})")
    
    choice = int(input("Number: ")) - 1
    selected = resources[choice]
    
    result = await client.read_resource(selected.uri)
    return result

Resources as context

Inject resources preemptively vào conversation:

Start chat với loaded context.

async def init_conversation_with_context(client, resource_uris):
    messages = []
    
    for uri in resource_uris:
        result = await client.read_resource(uri)
        content = format_content(result)
        messages.append({
            "role": "user",
            "content": f"Reference data:\n<{uri}>\n{content}\n</{uri}>"
        })
        messages.append({
            "role": "assistant",
            "content": f"Understood. I have access to {uri}."
        })
    
    return messages

Caching

Resources read-only → cache by URI:

Reduce server calls, speed up repeated access.

class CachedMCPClient:
    def __init__(self, base_client):
        self.client = base_client
        self._cache: dict[str, Any] = {}
        self._cache_ttl = 300  # 5 min
        self._cache_timestamps = {}
    
    async def read_resource(self, uri: str):
        now = time.time()
        
        if uri in self._cache:
            if now - self._cache_timestamps[uri] < self._cache_ttl:
                return self._cache[uri]
        
        result = await self.client.read_resource(uri)
        self._cache[uri] = result
        self._cache_timestamps[uri] = now
        return result
    
    def invalidate(self, uri: str = None):
        if uri:
            self._cache.pop(uri, None)
        else:
            self._cache.clear()

Combine với prompt caching (Anthropic)

Load resource, cache it with Anthropic prompt cache:

Resource content cached 1 giờ. Multiple queries on same doc → 90% cheaper.

result = await client.read_resource("docs://report.pdf")
content = format_content(result)

messages = [{
    "role": "user",
    "content": [
        {
            "type": "text",
            "text": f"Document: {content}",
            "cache_control": {"type": "ephemeral"}  # ← Anthropic cache
        },
        {
            "type": "text",
            "text": user_question  # dynamic part
        }
    ]
}]

Auto-suggest resources

Claude có thể mention resources trong response:

Client detect URIs → show link (clickable to view full).

User: What's in our Q4 plans?
Claude: Based on docs://plan.md, the key steps are...

Example: Mini IDE

Resources + tools + prompts = powerful agentic interface.

async def run_ide(client):
    print("Welcome to mini-IDE. Commands:")
    print("  ls              - list resources")
    print("  cat <uri>       - read resource")
    print("  chat <message>  - chat with Claude")
    
    while True:
        cmd = input("\n> ").strip()
        
        if cmd == "ls":
            resources = await client.list_resources()
            for r in resources:
                print(f"  {r.uri}  — {r.name}")
        
        elif cmd.startswith("cat "):
            uri = cmd[4:]
            result = await client.read_resource(uri)
            print(format_content(result))
        
        elif cmd.startswith("chat "):
            user_input = await expand_mentions(cmd[5:], client)
            # ... send to Claude

Anti-patterns

❌ Read resource every turn

Each query re-reads → slow + server load.

Fix: Cache client-side + Anthropic prompt cache.

❌ Inject all resources

Load everything at start → expensive, context overflow.

Fix: Lazy load on demand via @mentions.

❌ No error handling

Resource deleted → crash.

Fix: try-except, show graceful "unavailable".

Áp dụng ngay

Bài tập 1: @mention expander (25 phút)

Implement expand_mentions. Test: Summarize @docs://report.pdf.

Bài tập 2: Resource picker UI (20 phút)

CLI picker: list resources numbered, user select by number, read + show.

Tóm tắt

🎯 Client list_resources + read_resource basic ops.

🎯 @mention UX — user reference @uri → auto-expand.

🎯 Cache resources client-side + Anthropic prompt cache.

🎯 Resources as preloaded context cho conversations.

🎯 Read-only contract — no side effects on read.

Nội dung này có hữu ích không?