Skip to content

Commit 04d8f27

Browse files
zenshanda-ai
andcommitted
feat: add MCP service interfaces
Co-Authored-By: Anda Bot <noreply@anda.bot>
1 parent 3e73a6c commit 04d8f27

19 files changed

Lines changed: 1165 additions & 0 deletions

File tree

‎README.md‎

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,10 @@ Agent Identity
3434
+--> Agent Discourse -- may resolve --> third-party Agent Profile service
3535
```
3636

37+
## MCP Service Interfaces
38+
39+
Services that implement Agent Profile Protocol or Agent Discourse Protocol may also expose their capabilities through an MCP server for direct MCP client access. These MCP surfaces are adapters over the existing services, not new Agent Protocols. See [docs/mcp/service-interfaces/2025-11-25.md](docs/mcp/service-interfaces/2025-11-25.md).
40+
3741
## Maturity
3842

3943
All specifications in this repository are currently **drafts**. Implementers should expect clarifications, test vectors, JSON Schemas, and conformance tests to be added before a stable 1.0 release.
@@ -54,6 +58,8 @@ docs/
5458
agent-identity/
5559
agent-profile/
5660
agent-discourse/
61+
mcp/
62+
service-interfaces/
5763
```
5864

5965
## SDKs

‎README.zh-CN.md‎

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,10 @@ Agent Identity
3434
+--> Agent Discourse -- may resolve --> third-party Agent Profile service
3535
```
3636

37+
## MCP Service Interfaces
38+
39+
实现 Agent Profile Protocol 或 Agent Discourse Protocol 的服务也可以通过 MCP server 暴露服务能力,让 MCP client 直接连接调用。这些 MCP surface 是已有服务能力上的适配层,不是新的 Agent Protocols。参见 [docs/mcp/service-interfaces/2025-11-25.zh-CN.md](docs/mcp/service-interfaces/2025-11-25.zh-CN.md)。
40+
3741
## 成熟度
3842

3943
本仓库中的所有规范当前均为 **草案**。在稳定的 1.0 版本发布前,实现者应预期规范将会增加澄清说明、测试向量、JSON Schema 和一致性测试。
@@ -54,6 +58,8 @@ docs/
5458
agent-identity/
5559
agent-profile/
5660
agent-discourse/
61+
mcp/
62+
service-interfaces/
5763
```
5864

5965
## SDK

‎crates/agent-protocols/src/discourse.rs‎

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ use sha3::{Digest, Sha3_256};
1717

1818
use crate::error::{Result, SdkError};
1919
use crate::identity::{verify_envelope, AgentId, Envelope, Event};
20+
use crate::mcp::McpServiceInterfaceDiscovery;
2021

2122
pub const PROTOCOL: &str = "agent-discourse/1.0";
2223

@@ -474,6 +475,8 @@ pub struct DiscourseProtocolDiscovery {
474475
pub profile: Option<ProfileResolverMetadata>,
475476
#[serde(default, skip_serializing_if = "BTreeMap::is_empty")]
476477
pub endpoints: BTreeMap<String, String>,
478+
#[serde(default, skip_serializing_if = "Option::is_none")]
479+
pub mcp: Option<McpServiceInterfaceDiscovery>,
477480
}
478481

479482
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]

‎crates/agent-protocols/src/lib.rs‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ pub mod error;
99
#[cfg(feature = "http-client")]
1010
pub mod http_client;
1111
pub mod identity;
12+
pub mod mcp;
1213
pub mod profile;
1314

1415
pub use error::{Result, SdkError};

‎crates/agent-protocols/src/mcp.rs‎

Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
use serde::{Deserialize, Serialize};
2+
use serde_json::Value;
3+
use std::collections::BTreeMap;
4+
5+
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Eq)]
6+
pub enum McpAuthorizationMode {
7+
#[serde(rename = "none")]
8+
None,
9+
#[serde(rename = "agent-jwt")]
10+
AgentJwt,
11+
}
12+
13+
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Eq)]
14+
pub struct McpAuthorizationMetadata {
15+
pub mode: McpAuthorizationMode,
16+
#[serde(default, skip_serializing_if = "Option::is_none")]
17+
pub agent_jwt_audience: Option<String>,
18+
}
19+
20+
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Eq)]
21+
pub struct McpServiceInterfaceDiscovery {
22+
pub spec_version: String,
23+
pub endpoint: String,
24+
pub transport: String,
25+
#[serde(default, skip_serializing_if = "Option::is_none")]
26+
pub authorization: Option<McpAuthorizationMetadata>,
27+
#[serde(default, skip_serializing_if = "Vec::is_empty")]
28+
pub tools: Vec<String>,
29+
#[serde(default, skip_serializing_if = "Vec::is_empty")]
30+
pub resources: Vec<String>,
31+
#[serde(default, skip_serializing_if = "Vec::is_empty")]
32+
pub prompts: Vec<String>,
33+
#[serde(default, skip_serializing_if = "BTreeMap::is_empty")]
34+
pub extra: BTreeMap<String, Value>,
35+
}
36+
37+
#[cfg(test)]
38+
mod tests {
39+
use super::*;
40+
41+
#[test]
42+
fn mcp_service_interface_discovery_round_trips() {
43+
let discovery = McpServiceInterfaceDiscovery {
44+
spec_version: "2025-11-25".to_owned(),
45+
endpoint: "https://profiles.example.com/mcp".to_owned(),
46+
transport: "streamable-http".to_owned(),
47+
authorization: Some(McpAuthorizationMetadata {
48+
mode: McpAuthorizationMode::AgentJwt,
49+
agent_jwt_audience: Some("https://profiles.example.com".to_owned()),
50+
}),
51+
tools: vec!["agent_profile.get".to_owned()],
52+
resources: vec!["agent-profile://profiles/{agent_id}".to_owned()],
53+
prompts: Vec::new(),
54+
extra: BTreeMap::new(),
55+
};
56+
57+
let encoded = serde_json::to_value(&discovery).unwrap();
58+
assert_eq!(encoded["spec_version"], "2025-11-25");
59+
assert_eq!(encoded["authorization"]["mode"], "agent-jwt");
60+
assert!(encoded.get("prompts").is_none());
61+
62+
let decoded: McpServiceInterfaceDiscovery = serde_json::from_value(encoded).unwrap();
63+
assert_eq!(decoded, discovery);
64+
}
65+
}

‎crates/agent-protocols/src/profile.rs‎

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ use std::collections::BTreeMap;
44

55
use crate::error::{Result, SdkError};
66
use crate::identity::{verify_envelope, AgentId, Envelope, Event};
7+
use crate::mcp::McpServiceInterfaceDiscovery;
78

89
pub const PROTOCOL: &str = "agent-profile/1.0";
910
pub const PROFILE_UPDATE: &str = "profile.update";
@@ -114,6 +115,8 @@ pub struct ProfileServiceDiscovery {
114115
pub protocol: String,
115116
pub service: String,
116117
pub endpoints: ProfileServiceEndpoints,
118+
#[serde(default, skip_serializing_if = "Option::is_none")]
119+
pub mcp: Option<McpServiceInterfaceDiscovery>,
117120
#[serde(default, skip_serializing_if = "Vec::is_empty")]
118121
pub features: Vec<String>,
119122
}

0 commit comments

Comments
 (0)